Android音视频开发之MediaCodec的使用教程

目录
  • 前言
  • MediaCodec
    • 编解码流程
    • 生命周期
  • 接口简介

前言

获取到音视频轨道(编解码格式),知道设备支持哪些编解码器,下一步就是创建编解码器去实现数据流的编解码过程了。在Android开发中提供了实现音视频编解码工具MediaCodec,针对对应音视频解码类型通过该类创建对应解码器就能实现对数据进行解码操作。

MediaCodec

MediaCodec所支持的数据类型:压缩的音视频数据、原始音频数据和原始视频数据。 首先show代码,紧接着之前MediaExtactor提取资源,MediaCodecList遍历支持格式,确认设置支持该资源格式后通过MediaCodec创建解码器(这里是做视频解码播放)。

// 加载资源
extractor.setDataSource(path);
// 获取视频轨道
int trackIndex = getTrackIndex(extractor,"video/");
// 获取视频轨道参数
MediaFormatInfo mediaFormatInfo = MediaFormatInfo.buildUpVideoMediaFormatInfo(extractor.getTrackFormat(trackIndex));
// 选取上述的视频轨道
extractor.selectTrack(trackIndex);
MediaCodecInfo mediaCodecInfo = CodecInfoInstance.getInstance().selectDeCodec(mediaFormatInfo.getMime());
// 判断设备是否支持该视频解码,创建视频编码器
if(mediaCodecInfo != null){
    mediaCodec = MediaCodec.createDecoderByType(mediaFormatInfo.getMime());
    mediaCodec.configure(mediaFormatInfo.getMediaFormat(),surface,null,0);
}

编解码流程

  • MediaCodec的功能其实很简单通过一个数据缓冲去,将数据填充到输入缓冲区给到Codec
  • Codec通过异步方式处理输入缓冲区数据将处理好数据填充到输出缓冲区
  • 客户端从输出缓冲区获取到处理好的数据去消费,最后把缓冲区返还给Codec

部分代码实现

  • dequeueInputBuffer:从输入流队列取数据进行编码操作
  • getInputBuffers: 获取需要编码数据的输入队列 返回ByteBuffer数组
  • queueInoutBuffer: 输入流入队列
  • dequeueOutputBuffer: 从输入队列中取出编码操作结果数据
  • getOutPutBuffer: 获取编解码之后数据输出队列 返回一个ByterBuffer数组
  • releaseOutPutBuffer: 处理完成释放ByterBuffer数组
while (!isEnd && !isInterrupted()){
    if (!mIsEOS) {
        mIsEOS = dequeueInputBuffers();
    }
    isEnd = dequeueOutputBuffers();
}

//输入缓冲区
private boolean dequeueInputBuffers() {
    boolean isMediaEOS = false;
    //  等待编码器输入缓冲区数据出队
    int inputBufferId = mediaCodec.dequeueInputBuffer(TIMEOUT_US);
    if (inputBufferId >= 0) {
        // 获取缓存区数据
        ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferId);
        // 读取数据 返回值sampleSize大于0表示还有数据,否则表示结束
        int sampleSize = extractor.readSampleData(inputBuffer, 0);
        if (sampleSize < 0) {
            // 数据末尾 必须再次调用queueInputBuffer使用BUFFER_FLAG_END_OF_STREAM标识符输入到编码器
            mediaCodec.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            isMediaEOS = true;
            MediaLogUtils.printI(TAG + "end of stream");
        } else {
            // 输入缓冲区数据入队
            mediaCodec.queueInputBuffer(inputBufferId, 0, sampleSize, extractor.getSampleTime(), 0);
            extractor.advance();
        }
    }
    return isMediaEOS;
}

//输出缓冲区
private synchronized boolean dequeueOutputBuffers() {
    MediaCodec.BufferInfo outBufferInfo = new MediaCodec.BufferInfo();
    //输出缓冲区
    int outputBufferId = mediaCodec.dequeueOutputBuffer(outBufferInfo, TIMEOUT_US);
    switch (outputBufferId) {
        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
            MediaLogUtils.printI(TAG+"INFO_OUTPUT_FORMAT_CHANGED");
            break;
        case MediaCodec.INFO_TRY_AGAIN_LATER:
            MediaLogUtils.printI(TAG+ "INFO_TRY_AGAIN_LATER");
            break;
        case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
            MediaLogUtils.printI(TAG+ "INFO_OUTPUT_BUFFERS_CHANGED");
            break;
        default:
            // 延迟解码
            decodeDelay(outBufferInfo, mStartMs);
            // 释放输出缓冲区数据 render为true渲染到surface上
            mediaCodec.releaseOutputBuffer(outputBufferId, true);
            break;
    }
    // 结尾
    if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
        MediaLogUtils.printI(TAG+"buffer stream end");
        return true;
    }
    return false;
}

生命周期

MediaCodec生命周期分为三种状态:StoppedExecutingReleased

  • Stopped具有三种子状态:Uninitialized、Configured、Error
  • Executing具有三种子状态:Flushed、Running、End-of-Stream

Stopped

Uninitialized: UninitializedMediaCodec创建后初始状态。可通过reset()复位到Uninitialized

Configured: MediaCodec通过configure方法设置配置(编解码器类型等)进入到Configured状态。

Error: MediaCodec发生异常情况下会进入Error状态。

Executing

Flush:MediaCodec调用start方法后进入FlushedMediaCodec就具备所有缓存能力。若可以在Executing,调用flush()回到Flushed状态。

Running: 当第一次InputBuffer输入缓存被移除队列,MediaCodec就会进入到Running状态。

End-of-Stream:将end-of-stream标记输入InputBuffer队列,MediaCodec就会进入到 End-of-Stream状态,MediaCodec就不再接收InputBuffer,但不影响输出队列OutBuffer产出直到end-of-stream标记输出为止(输入和输出中间是有一定处理时间)。

接口简介

createDecoderByType/createEncoderByType,创建解码器/编码器对象

createByCodecName,根据编解码器名称创建

configure,配置编解码器配置

start,配置完成后需要执行start完成配置

dequeueInputBuffer, 输入队列取数据编码操作

queueInputBuffer,输入入队列

dequeueOutputBuffer,从输出队列取出编码操作后的数据

releaseOutputBuffer,释放输出队列释放ByteBuffer数据

getInputBuffers,获取需要编码数据输入流队列,返回ByteBuffer数组

getOutputBuffers,获取编解码后数据输出流队列,返回ByteBuffer数组

flush,清空输入和输出端口

stop,终止decode/encode会话

release,释放编解码器资源

参考文章

到此这篇关于Android音视频开发之MediaCodec的使用教程的文章就介绍到这了,更多相关Android MediaCodec内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android音视频开发之MediaExtactor使用教程

    目录 前言 MediaExtactor 使用MediaExtactor 加载音视频文件代码 获取轨道代码 提取轨道数据信息 一些源码细节分析 前言 在之前学习如何使用MediaPlayer后,了解到Android系统提供开发者播放多媒体全家桶能力,但对于开发者希望DIY自由度更高的播放器能力也是可以利用Android内部提供组件包自行实现一个播放器的.举例实现一个视频播放这个流程,它大致流程是[多媒体文件解析提取视频文件]-> [视频流解码]-> [解码数据播放渲染到Render].首要需要实

  • Android开发MediaCodec和lamemp3多段音频截取拼接

    目录 AudioHolder.java属性类 SimpleLame.java调用lamemp3类 native-lib.cpp AudioMerge.java拼接操作类 使用 截取很简单,只要用MediaCodec进行解码解出pcm格式的数据,再把pcm数据用MediaCodec进行编码或者用其他第三方的进行编码 . 拼接就比较麻烦,音频的音质会受到采样率,比特率和声道的影响,所以理想的状态是这三个属性要一样进行拼接才能保证音质 . 举个栗子,a和b是两首采样率,比特率和声道都不一样的歌,要拼接

  • Android音视频开发之MediaPlayer使用教程

    目录 MediaPlayer 简单使用 缺陷 AndroidMediaPlayer播放器封装 状态机编写 内部类 初始化函数 方法和回调 小结 MediaPlayer Android多媒体框架支持播放提供了MediaPlayerAPI,可以通过MediaPlayer来实现媒体文件播放.可以说MediaPlayer是非常方便使用的多媒体播放器,只需要简单设置就能实现对音频和视频播放功能,其内部帮助开发者实现了播放对象获取解码以及播放功能. 简单使用 MediaPlayer支持多种资源形式:本地资源

  • Android使用MediaCodec将摄像头采集的视频编码为h264

    本文实例为大家分享了Android使用MediaCodec将摄像头采集的视频编码为h264,供大家参考,具体内容如下 MainActivity.java import android.app.Activity; import android.graphics.ImageFormat; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.hardware.Camera.P

  • Android音频开发之SurfaceView的使用详解

    目录 SurfaceView 不同点 双缓冲机制 SurfaceHolder 使用 SurfaceView SurfaceView从源码上看继承自View,但在内部实现上SurfaceView和其他View有很多区别. SurfaceView主要作用是提供一个直接绘图表面嵌入到视图结构中,实际上真正做绘制能力的是Surface.因此SurfaceView和宿主窗口是分离的.正常情况下窗口的View共享同一个Window,而Window也对应一个Surface,所有View也就共享同一个Surfa

  • Android音视频开发之MediaCodec的使用教程

    目录 前言 MediaCodec 编解码流程 生命周期 接口简介 前言 获取到音视频轨道(编解码格式),知道设备支持哪些编解码器,下一步就是创建编解码器去实现数据流的编解码过程了.在Android开发中提供了实现音视频编解码工具MediaCodec,针对对应音视频解码类型通过该类创建对应解码器就能实现对数据进行解码操作. MediaCodec MediaCodec所支持的数据类型:压缩的音视频数据.原始音频数据和原始视频数据. 首先show代码,紧接着之前MediaExtactor提取资源,Me

  • Android音视频开发之VideoView使用指南

    目录 VideoView介绍 MediaController 使用 源码分析 进度显示 播放尺寸适配 VideoView介绍 之前介绍过使用MediaPlayer+SurfaceView实现播放视频功能.无意间发现官方封装了VideoView组件来实现简单视频播放功能,内部同样是使用MediaPlayer+SurfaceView的形式控制MediaPlayer对视频文件进行播放.使用场景比较简单,适用于只是播放视频的场景,其提供能力有限不太适合使用在调节视频亮度等其他功能. MediaContr

  • Android音视频开发Media FrameWork框架源码解析

    目录 一.Media FrameWork背景 二.Media Framework“路线图” 2.1 代理端 2.2 服务端 2.2.1 Source 2.2.2 Decoder 2.2.3 Renderer 2.2.4 Foundation 2.3 OMX端 2.4 Kernel端 三.media播放的流程 四.Media FrameWork源码分析 一.Media FrameWork背景 Media Framework (媒体函数库):此函数库让Android 可以播放与录制许多常见的音频与视

  • Android音视频之视频采集(系统API预览)

    我们了解了视频相关的基础知识,后面的文章我们要能够和音频一样可以采集我们的视频,视频是一帧一帧的图片来的,我们首先要学习预览视频,然后采集一帧图片,采集视频从简到难的来了解这个问题.首先第一个反应打开Google搜索和Android视频采集相关的东西,我们要知道如何通过API来采集,不由自主地到了Android官网的Camera API.Android有两个视频采集的API,Camera是Android 5.0以前使用的,现在已经废弃了,我们还是得学一下他的使用,Camera2是最新的视频采集A

  • 微信小程序开发之map地图实现教程

    前言 微信小程序地图操作比较简单,api也很少,使用map组件来展示.说到地图,那就先来看基础定位: 定位用到wx.getLocation(OBJECT)函数,代码如下: wx.getLocation({ type: 'wgs84', success: function(res) { var latitude = res.latitude var longitude = res.longitude var speed = res.speed var accuracy = res.accuracy

  • Android开发之MediaPlayer多媒体(音频,视频)播放工具类

    本文实例讲述了Android开发之MediaPlayer多媒体(音频,视频)播放工具类.分享给大家供大家参考,具体如下: package com.android.imooc.chat; import java.io.IOException; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; impor

  • Android NDK开发之FFmpeg视频添加水印

    目录 前言 1.FFmpeg添加水印命令 1.1.水印命令 1.2.命令补充说明 2.Android 核心代码 2.1.jni Java声明 2.2.核心代码ffmpeg.c 2.3调用程序 3.运行结果 3.1原视频播放 3.2添加水印 前言 Android也是利用FFmpeg命令行的形式(混编),进行视频转码压缩. 1.FFmpeg添加水印命令 1.1.水印命令 ffmpeg -iWildlife.wmv-vf "movie=panda.png[watermark];[in][waterma

  • Android开发之ContentProvider的使用详解

    前言         Content Provider为存储数据和获取数据提供了统一的接口,它可以完成在不同应用程序下的数据共享,而在上一篇文章Android开发之SQLite的使用方法讲到的SQLite只能在同一个程序中共享数据.另外android为一些常见的数据,比如说音频,视频,图片,通讯录等提供了Content Provider,这样我们就可以很方便的对这些类型的数据操作了.使用ContentProvider的好处是开发人员不需要考虑数据内部是怎么存储的,比如说如果我们想利用Conten

随机推荐