我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android音视频开发之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内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android音视频开发之MediaExtactor怎么使用

本文小编为大家详细介绍“Android音视频开发之MediaExtactor怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android音视频开发之MediaExtactor怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢
2023-06-30

Android音视频开发只硬件解码组件MediaCodec讲解

在Android开发中提供了实现音视频编解码工具MediaCodec,针对对应音视频解码类型通过该类创建对应解码器就能实现对数据进行解码操作。本文通过示例详细讲解了MediaCodec的使用,需要的可以参考一下
2023-01-06

Android开发之音视频协议分析

这篇文章主要介绍“Android开发之音视频协议分析”,在日常操作中,相信很多人在Android开发之音视频协议分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android开发之音视频协议分析”的疑惑有所
2023-06-30

Android音视频开发中VideoView怎么使用

这篇文章主要介绍“Android音视频开发中VideoView怎么使用”,在日常操作中,相信很多人在Android音视频开发中VideoView怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Andro
2023-06-30

Qt音视频开发之音频播放QAudioOutput的实现

这篇文章主要为大家详细介绍了如何利用Qt实现音频播放QAudioOutput功能,文中的示例代码讲解详细,对我们学习Qt开发有一定的帮助,需要的可以参考一下
2023-03-10

Qt音视频开发之视频文件保存功能的实现

和音频存储类似,视频的存储也对应三种格式,视频最原始的数据是yuv(音频对应pcm),视频压缩后的数据是h264(音频对应aac)。本文将利用Qt实现视频文件保存功能,感兴趣的可以了解一下
2022-12-08

android开发教程之android的handler使用方法

Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title.首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示:代码如下:pack
2022-06-06

Android开发笔记之Fragment的使用教程

我们的Android入门一步步已经进入中级,我们讲完了所有的基本组件的基本使用、Activity、Service、BroadCast,今天我们来介绍一下Fragment的使用教程,需要的朋友可以参考下
2023-05-19

使用QT调用FFMPEG库部署到Android设备、完成视频音频应用开发

系统环境: ubuntu18.04 FFMPEG版本: 4.2.2 测试的Android 平板系统:  Android8.1 第一步: 编译Android设备能使用的FFMPEG库 参考这篇文章: https://blog.csdn.net
2022-06-06

PHP Websocket开发教程,构建实时音视频通话功能

PHP Websocket开发教程,构建实时音视频通话功能简介:实时音视频通话是现代互联网应用中非常常见和重要的功能之一。而PHP作为一种广泛使用的服务器端语言,通过使用Websocket技术,也能够实现实时音视频通话的功能。本文将介绍如何
PHP Websocket开发教程,构建实时音视频通话功能
2023-12-18

android开发教程之startActivityForResult使用方法

最近做的一个小东西遇到这样的情况,我从一个页面MainActivity修改一些内容,需要跳转到一个新的EditActivity去做修改操作,修改完成后就回到之前的MainActivity,因为信息被修改了,最好还是从服务器上重新获取一下,那
2022-06-06

android开发教程之listview使用方法

首先是布局文件,这里需要两个布局文件,一个是放置列表控件的Activity对应的布局文件 main.xml,另一个是ListView中每一行信息显示所对应的布局 list_item.xml 这一步需要注意的问题是ListView 控
2022-06-06

Android开发之多媒体文件获取工具类实例【音频,视频,图片等】

本文实例讲述了Android开发之多媒体文件获取工具类。分享给大家供大家参考,具体如下:package com.android.ocr.util;import java.io.File;import java.util.ArrayList;
2023-05-30

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录