Android MediaCodec 编码使用介绍

本文介绍了如何在Android平台上使用MediaCodecAPI进行视频编码。首先通过MediaCodecList获取编解码器信息,然后设置编码参数如分辨率、比特率和帧率,接着实例化并配置编码器,启动编码过程。在编码阶段,将数据输入到编码器并处理输出缓冲区,从而实现视频的编码操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

想要了解安卓的编解码,首先要从api的使用开始,下面介绍一下使用MediaCodec的使用流程。

  • Java层API使用介绍

编码篇:

1、获取编解码器信息

首先我们需要获取Codec的信息,通过MediaCodecList这个类来实现获取到MediaCodecInfo,代码示例如下:

int numCodecs = MediaCodecList.getCodecCount();
for (int i = 0; i < numCodecs; i++) {
    MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
    if (!codecInfo.isEncoder()) {
        continue;
    }
    String[] types = codecInfo.getSupportedTypes();
    for (int j = 0; j < types.length; j++) {
        if (types[j].equalsIgnoreCase(mimeType)) {
            return codecInfo;
        }
    }
}
这里我们需要设置mimeType,这是一个字符串比如我们需要设置avc格式的视频那么我们可以将其设置为

setMineType("video/avc");

然后选择合适我们的编码器
 

 

2、设置编码参数

设置编码参数通过mediaFormat来实现,代码·示例如下:

首先创建MediaFormat实例

mediaFormat = MediaFormat.createVideoFormat(mineType, INPUT_WIDTH, INPUT_HEIGHT);//这里我们需要指定mimeType以及编码后的宽高

然后通过mediaFormat来设置参数如下:

mediaFormat = MediaFormat.createVideoFormat(mineType, INPUT_WIDTH, INPUT_HEIGHT);
//mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 21);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 4 * 1024 * 1024*1024);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 4);
mediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate); //帧率
mediaFormat.setInteger ("vendor.qti-ext-enc-bitrate-mode.value",2);//这里为高通特有参数,我们可以根据不同的芯片平台设置他们独有的功能(需要参考平台文档),比如这里就可以指定码率的模式

3、实例化编码器

mCodec = MediaCodec.createByCodecName(codecInfo.getName());

4、配置编码器

mCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

这里可以将之前设置的编码参数设置到编码器中,这里需要提示的一点是第二参数为null是不指定surface,当然如果有我们可以指定。不指定系统会为我们默认创建。

第三个参数nll代表加密。第四个参数指定我们需要做的动作,本次我们指定编码。

5、使能编码器

mCodec.start();

这里codec进入待定状态,随时可以接收输入流进行编码

6、准备编码数据源

//解码后获取buffer元数据信息
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

long timeoutUs = 12*1000;
long mEndTime = 0L;
long curretTime = 0L;
boolean isFirstFrame = true;

ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();

if(mInputSource != 0){
    inputStream = mContext.getResources().openRawResource(mInputSource);

}


//拆分inputStream 将每张yuv数据储存到向量数组里
Vector<byte[]> bytesInputYUV = new Vector<>();
//提取yuv图像
try {
    for(int i=0; i < YUV_NUM_IN_RAW; i++){
        byte[] oneYUVPic = new byte[INPUT_WIDTH*INPUT_HEIGHT*3/2];
        inputStream.read(oneYUVPic,0,INPUT_WIDTH*INPUT_HEIGHT*3/2);
        bytesInputYUV.add(oneYUVPic);
    }

    inputStream.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}



7、进入编码阶段

Calendar calendar = Calendar.getInstance();
long startMils = calendar.getTimeInMillis();
Log.d(TAG,"Start time "+calendar.getTime());
int inputCount =0;
long startTime = System.nanoTime();
long encodeTime;
while (!mStopFlag){

    int inputBufferId = mediaCodec.dequeueInputBuffer(timeoutUs);
    //准备数据并且将其dequeue到inputBuffer
    if(inputBufferId >= 0){
        ByteBuffer inputBuffer = inputBuffers[inputBufferId];
        if(inputCount++ == 2700)//编码满2700后结束
            break;
        byte[] data = bytesInputYUV.get(inputCount%YUV_NUM_IN_RAW);
        inputBuffer.put(data,0,data.length);
        encodeTime = (System.nanoTime() - startTime)/1000+100;
        mediaCodec.queueInputBuffer(inputBufferId,0,data.length,encodeTime,0);
        inputBuffer.clear();
    }


    int outpueBufferId = mediaCodec.dequeueOutputBuffer(bufferInfo,timeoutUs);
    if(outpueBufferId >= 0){
        startTime = System.currentTimeMillis();
        ByteBuffer outputBuffer = outputBuffers[outpueBufferId];
        byte[] outStream = new byte[bufferInfo.size];
        outputBuffer.get(outStream,0,bufferInfo.size);
        try {
            fileOutputStream.write(outStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        outCount++;
        if(outCount%60 == 0){
            Log.d(TAG,"inputCount : "+inputCount+" outCount : "+outCount);
        }
        mediaCodec.releaseOutputBuffer(outpueBufferId,0);
        curretTime = System.currentTimeMillis();
        if(isFirstFrame){
            isFirstFrame = false;
            mEndTime = curretTime;
        }else {
            long elapsedTime = curretTime - mEndTime;
            timeTotal++;
        }
    }

}
try {
    fileOutputStream.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}


代码示例链接:


AndroidMediaCodecTest: 用来演示安卓的基本编解码功能

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super Jang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值