Android音视频编码(3)

发布时间:2024年01月21日

继续Android音视频编码(2)中的内容,在上一篇文章中,对视频解码和编码进行了详细的介绍,具体可参见这里

视频解码 Surface播放

    @Override
    public void start(){
        super.start();
        mediaCodec.setCallback(new MediaCodec.Callback() {
            @Override
            public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
                ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);
                int size = extractor.readBuffer(inputBuffer, true);
                long st = extractor.getSampleTime();
                if (size >= 0) {
                    codec.queueInputBuffer(
                            index,
                            0,
                            size,
                            st,
                            extractor.getSampleFlags()
                    );
                } else {
                    //结束
                    codec.queueInputBuffer(
                            index,
                            0,
                            0,
                            0,
                            BUFFER_FLAG_END_OF_STREAM
                    );
                }
            }

            @Override
            public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
...

            }

            @Override
            public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
                codec.stop();
            }

            @Override
            public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {

            }
        });
        mediaCodec.configure(mediaFormat,mSurface,null,0);
       //mediaCodec.configure(mediaFormat,null,null,0);
        mediaCodec.start();
    }

通过这行 mediaCodec.configure(mediaFormat,mSurface,null,0)代码就可以将解码后的数据在相应的surface中进行预览播放。

音频解码

这里是音频解码的参考代码。

package com.example.myapplication.media.codec.async;

import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;

import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;

/**
 * describe:
 */
public class AsyncAudioDecode extends BaseAsyncDecode {
    private static final String TAG = "AsyncAudioDecode";
    private int mPcmEncode;
    //一帧的最小buffer大小
    private  int mMinBufferSize;
    private AudioTrack mAudioTrack;

    public AsyncAudioDecode(long progress) {
        super(progress);
        //拿到采样率
        if (mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) {
            mPcmEncode = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);
        } else {
            //默认采样率为 16bit
            mPcmEncode = AudioFormat.ENCODING_PCM_16BIT;
        }

        //音频采样率
        int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
        //获取视频通道数
        int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);

        //拿到声道
        int channelConfig = channelCount == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO;
        mMinBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, mPcmEncode);


        /**
         * 设置音频信息属性
         * 1.设置支持多媒体属性,比如audio,video
         * 2.设置音频格式,比如 music
         */
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();
        /**
         * 设置音频数据
         * 1. 设置采样率
         * 2. 设置采样位数
         * 3. 设置声道
         */
        AudioFormat format = new AudioFormat.Builder()
                .setSampleRate(sampleRate)
                .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                .setChannelMask(channelConfig)
                .build();


        //配置 audioTrack,采用流模式
        mAudioTrack = new AudioTrack(
                attributes,
                format,
                mMinBufferSize,
                AudioTrack.MODE_STREAM,
                AudioManager.AUDIO_SESSION_ID_GENERATE
        );
        //监听播放
        mAudioTrack.play();
    }

    @Override
    public void start(){
        super.start();
        mediaCodec.setCallback(new MediaCodec.Callback() {
            @Override
            public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
                ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);
                int size = extractor.readBuffer(inputBuffer, false);
                if (size >= 0) {
                    codec.queueInputBuffer(
                            index,
                            0,
                            size,
                            extractor.getSampleTime(),
                            extractor.getSampleFlags()
                    );

                } else {
                    //结束
                    codec.queueInputBuffer(
                            index,
                            0,
                            0,
                            0,
                            MediaCodec.BUFFER_FLAG_END_OF_STREAM
                    );

                }
            }

            @Override
            public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
                Message msg = new Message();
                msg.what = MSG_AUDIO_OUTPUT;
                msg.arg1 = index;
                msg.arg2 = info.size;
                mHandler.sendMessage(msg);
            }

            @Override
            public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
                codec.stop();
            }

            @Override
            public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {

            }
        });
        mediaCodec.configure(mediaFormat, null, null, 0);
        mediaCodec.start();
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        switch (msg.what){

            case MSG_AUDIO_OUTPUT:
                int index = msg.arg1;
                int size = msg.arg2;
                ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(index);
                try {
                    if (outputBuffer != null) {
                        mAudioTrack.write(outputBuffer, size,AudioTrack.WRITE_BLOCKING);
                        mediaCodec.releaseOutputBuffer(index, false);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;

            default:break;
        }
        return super.handleMessage(msg);
    }


    @Override
    public void stop() {
        super.stop();
        //释放 AudioTrack
        if (mAudioTrack.getState() != AudioTrack.STATE_UNINITIALIZED) {
            try {
                mAudioTrack.stop();
            }catch (Exception e){

            }
        }
    }

    @Override
    public void release() {
        super.release();
        mAudioTrack.release();
    }

    @Override
    protected int decodeType() {
        return AUDIO;
    }
}

由于这个例子不需要对音频进行解码。这里直接使用。可参考则这段代码,先添加音频轨道,然后读取音频数据到buffer中,最后通过mediaMuxer将音频混合到视频当中。

    @SuppressLint("WrongConstant")
    public void encodeAudio() {
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
        if (audioFormat != null) {
            //写完视频,再把音频混合进去
            int audioSize = 0;
            //读取音频帧的数据,直到结束
            while ((audioSize = audioExtractor.readBuffer(buffer, false)) > 0) {
                bufferInfo.offset = 0;
                bufferInfo.size = audioSize;
                bufferInfo.presentationTimeUs = audioExtractor.getSampleTime();
                bufferInfo.flags = audioExtractor.getSampleFlags();
                mediaMuxer.writeSampleData(audioTrack, buffer, bufferInfo);
            }
        }
    }

更多内容,欢迎关注我的微信公众号:半夏之夜的无情剑客。

文章来源:https://blog.csdn.net/helloworlddm/article/details/135727390
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。