手机mp3转ogg格式 android播放mp3文件( 四 )


编码数据原始音频数据原始视频数据MediaCodec的状态管理MediaCodec存在三种状态:停止(stoped)、执行(executing)、释放(released) 。
停止状态:包含三个子状态:配置(configured)、未初始化(uninitialized)、错误(error)执行状态:包含三个子状态:刷新(flushed)、运行(running)、结束流(end-of-stream)MediaCodec 发展
Android系统中关于MediaCodec的介绍 , 可以参考Android的官方网站提供的信息:https://developer.android.google.cn/reference/kotlin/android/media/MediaCodec
MediaCodec 是在 Android 4.1版本(API16 )中出现并可用的 , 它提供了一种极其原始的接口 。MediaCodec类同时存在 Java和C++层中 , 但是只有前者是公共访问 ***。
在Android 4.3 (API18)中 , MediaCodec被扩展为通过 Surface 提供输入的 *** (通过 createInputSurface *** ) , 允许来自于相机的预览或者是经过OpenGL ES呈现 。在该版本中 , MediaCodec是之一个过了CTS测试的版本 。所谓的CTS , 全称是Compatibility Test Suite , 主要是google推出的一种设备兼容性测试规范 , 用来保证不同设备一致的用户体验的规范 。
除此之外 , 4.3版本还引入了 MediaMuxer 。MediaMuxer允许将AVC编解码器(原始H.264基本流)的输出转换为.MP4格式 , 可以和音频流一起转码也可以单独转换 。
音视频编辑MediaCodec通常与MediaExtractor、MediaSync、MediaMuxer、MediaCrypto、MediaDrm、Image、Surface和AudioTrack一起使用 , 几乎可以实现大部分音视频相关功能 。主要的操作步骤如下所示:
1、初始化 。2、MediaExtractor:提取音视频编码数据 , MediaExtractor用于对音视频文件解封装 , 提取出已编码的媒体数据 。3、MediaCodec:使用解码器进行解码 。4、处理:对音视频进行处理 。5、编码:使用MediaCodec编码器对音视频数据编码 。6、合成:MediaMuxer合成音视频文件 。MediaMuxer用于封装编码后的音视频数据 , 目前支持MP4、Webm和3GP文件作为输出 。7、 释放资源 。代码中的体现如下:
- createEncoderByType/createDecoderByType- configure- start- while(true) {- dequeueInputBuffer- queueInputBuffer- dequeueOutputBuffer- releaseOutputBuffer}- stop- release使用MediaCodec编码音频初始化MediaCodec对象 , 如下所示:private static MediaCodec createAudioEncoder() throws IOException {MediaCodec codec = MediaCodec.createEncoderByType(AUDIO_MIME);MediaFormat format = new MediaFormat();format.setString(MediaFormat.KEY_MIME, AUDIO_MIME);format.setInteger(MediaFormat.KEY_BIT_RATE, 64000);format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);return codec; }读取PCM数据 , 执行编码操作 。...while (!sawOutputEOS) {if (!sawInputEOS) {inputBufIndex = audioEncoder.dequeueInputBuffer(10_000);if (inputBufIndex >= 0) {ByteBuffer inputBuffer = audioInputBuffers[inputBufIndex];//先清空缓冲区inputBuffer.clear();int bufferSize = inputBuffer.remaining();if (bufferSize != rawInputBytes.length) {rawInputBytes = new byte[bufferSize];}//读取readRawAudioCount = fisRawAudio.read(rawInputBytes);//判断是否到文件的末尾if (readRawAudioCount == -1) {readRawAudioEOS = true;}if (readRawAudioEOS) {audioEncoder.queueInputBuffer(inputBufIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);sawInputEOS = true;} else {//放入缓冲区inputBuffer.put(rawInputBytes, 0, readRawAudioCount);rawAudioSize += readRawAudioCount;//放入编码队列audioEncoder.queueInputBuffer(inputBufIndex, 0, readRawAudioCount, audioTimeUs, 0);audioTimeUs = (long) (1_000_000 * ((float) rawAudioSize / AUDIO_BYTES_PER_SAMPLE));}}}?//输出端outputBufIndex = audioEncoder.dequeueOutputBuffer(outBufferInfo, 10_000);if (outputBufIndex >= 0) {// Simply ignore codec config buffers.if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {Log.i(TAG, "audio encoder: codec config buffer");audioEncoder.releaseOutputBuffer(outputBufIndex, false);continue;}if (outBufferInfo.size != 0) {ByteBuffer outBuffer = audioOutputBuffers[outputBufIndex];outBuffer.position(outBufferInfo.offset);outBuffer.limit(outBufferInfo.offset + outBufferInfo.size);//Log.v(TAG, String.format(" writing audio sample : size=%s , presentationTimeUs=%s", outBufferInfo.size, outBufferInfo.presentationTimeUs));if (lastAudioPresentationTimeUs <= outBufferInfo.presentationTimeUs) {lastAudioPresentationTimeUs = outBufferInfo.presentationTimeUs;int outBufSize = outBufferInfo.size;int outPacketSize = outBufSize + 7;outBuffer.position(outBufferInfo.offset);outBuffer.limit(outBufferInfo.offset + outBufSize);byte[] outData = https://www.juguize.com/b/new byte[outPacketSize];addADTStoPacket(outData, outPacketSize);outBuffer.get(outData, 7, outBufSize);fosAccAudio.write(outData, 0, outData.length);//Log.v(TAG, outData.length +" bytes written.");} else {Log.e(TAG, "error sample! its presentationTimeUs should not lower than before.");}}audioEncoder.releaseOutputBuffer(outputBufIndex, false);if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {sawOutputEOS = true;}} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {audioOutputBuffers = audioEncoder.getOutputBuffers();} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {MediaFormat audioFormat = audioEncoder.getOutputFormat();Log.i(TAG, "format change : " + audioFormat);}}...以上是MediaCodec的编码执行操作 。如果是解码 , 与编码过程相反即可完成 。

推荐阅读