想要了解安卓的编解码,首先要从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: 用来演示安卓的基本编解码功能