MediaCodec编码
原因:由于涉及到yuv的编码故使用android自带的MediaCodec模块进行硬件编码
概况:通过获取编码设备信息创建编码对象,然后设置编码参数,通过输入输出缓冲区进行数据的传递和读取。
流程如下:
首先获取当前设备支持的编解码设备信息:首先获取codc个数,然后判断是否是编码codec.
m_codeccount = MediaCodecList.getCodecCount();//获取codec个数for(int i=0;i<m_codeccount;i++)
{MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);//获取codecinfoif(info.isEncoder())//判断当前codec是否支持编码{String[] str = info.getSupportedTypes();//获取支持的类型}
}
通过上面获取的Codec类型有如下:
Type==audio/3gpp Name==OMX.google.amrnb.encoder
Type==audio/amr-wb Name==OMX.google.amrwb.encoder
Type==video/hevc Name==OMX.qcom.video.encoder.hevc
Type==video/mp4v-es Name==OMX.qcom.video.encoder.mpeg4
Type==video/avc Name==OMX.qcom.video.encoder.avc
根据获取的Codec类型和名字创建编码设备如下:可以看出有两种方式进行创建Codec.当前设备小米5S,如果使用ByName则会发现最后关键帧间隔设施不起作用,且最终输出的帧没有B帧.而使用ByType则可以使关键帧间隔生效和生成B帧.具体内部原因希望有了解的同学解惑。
m_codec = MediaCodec.createByCodecName(m_strName);m_codec = MediaCodec.createEncoderByType(m_strType);
创建完成Codec后就是设置编码参数,此时涉及到有些参数没有设置最终Configure失败的问题:
vformat.setInteger(MediaFormat.KEY_FRAME_RATE,m_Fps);//帧率
vformat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,m_Gop);//关键帧间隔单位为秒
vformat.setInteger(MediaFormat.KEY_WIDTH,m_W);//宽
vformat.setInteger(MediaFormat.KEY_HEIGHT,m_H);//高
vformat.setInteger(MediaFormat.KEY_BITRATE_MODE,m_Mode);//编码模式 目前使用CBR
vformat.setInteger(MediaFormat.KEY_BIT_RATE,m_BitRate * 1000);//单位为bps
vformat.setInteger(MediaFormat.KEY_COLOR_FORMAT,m_Color);//样本类型,目前只有420p和420sp两种.
vformat.setInteger(MediaFormat.KEY_PROFILE,m_Profile);//目前使用main
vformat.setInteger(MediaFormat.KEY_LEVEL,m_Level);//目前使用2.0m_codec.configure(vformat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);//配置编码信息
配置完成后需要使流程启动:通过介绍可以看出该方法必须在configure之后调用
m_codec.start();//成功配置完成后调用开始
获取输入和输出队列缓存区,用于输入和输出数据:通过介绍可以看出必须在start之后调用。可以简单理解为start内部完成了缓冲区的初始化和连接。
m_InputBuffer = m_codec.getInputBuffers();//获取输入缓冲区 需要start之后调用.m_OutputBuffer = m_codec.getOutputBuffers();//获取输出缓冲区
接下来进行输入数据进行编码,此时涉及到两种方式一种为同步,一种为异步,异步的话需要实现MeidaCodec.Callback接口,通过内部提供的接口函数实现数据的传递和读取,而同步则只需进行同步调用即可如下:细节为时间戳设置,如果时间戳没有设置那么就会导致取数据失败的问题。
int iIndex = m_codec.dequeueInputBuffer(m_TimeDelay);//获取一个可用的输入缓冲区,当前延时时间手动设置,-1:表示INFINITE
if (iIndex >= 0) {ByteBuffer input = m_InputBuffer[iIndex];//获取输入队列中一个空闲的成员input.clear();input.put(data, 0, iSize);//填充数据long presentationtimeus =1000 * (iCount * 20);//用于设置时间戳 microsecondsm_codec.queueInputBuffer(iIndex, 0, iSize, presentationtimeus,0);//填充一个ByteBuffer到输入队列,最后一个参数}else{Log.d(TAG,"dequeueInputBuffer Failed.");return false;}
数据读取如下:细节为缓存的回收,否则会导致传入数据时获取缓存阻塞.
//同步获取编码后数据
int iIndex2 = m_codec.dequeueOutputBuffer(m_pBufferInfo, m_TimeDelay);
if (iIndex2 >= 0)
{ByteBuffer output = m_OutputBuffer[iIndex2];output.position(m_pBufferInfo.offset);//设置缓冲区起始位置output.limit(m_pBufferInfo.offset + m_pBufferInfo.size);//设置缓冲区有效区间output.get(outData,0,m_pBufferInfo.size);//将有效数据写入数组iLen[0] = m_pBufferInfo.size;Log.d(TAG,"output offset="+m_pBufferInfo.offset+"Size"+m_pBufferInfo.size);m_codec.releaseOutputBuffer(iIndex2,false);//回收缓存
}
关键帧强制输出代码:设置一次后将会一直输出I帧,如何取消?
if(iCount % 10 == 0)设置一次将会一直输出I帧
{ Bundle params = new Bundle();params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);m_codec.setParameters(params);//app level 19 //强制I帧Log.d(TAG,"setParameters");
}
问题:利用MediaCodec如何设置B帧输出?强制关键帧输出?
总结:以上就是利用MeidaCodec实现的编码和遇到的问题,暂时没法解决,后续解决,如果有道友知道希望能够告知。
MediaCodec编码相关推荐
- MediaCodec 编码H264 编码一帧后dequeueOutputBuffer为-1的问题
在用android MediaCodec编码h264的时候,会遇到,dequeueOutputBuffer在成功获取到config帧(sps pps)及第一个I帧后,dequeueOutputBuff ...
- (二)音视频:MediaCodec编码桌面信息 完整Demo 进一步理解H264
(一)音视频:解码H264文件流程 渲染和拿到解码后源数据YUV 完整Demo] (二)音视频:MediaCodec编码桌面信息 完整Demo 进一步理解H264 (三)音视频:解析H264 SPS ...
- 研究Android音视频-3-在Android设备上采集音视频并使用MediaCodec编码为H.264
原文 : https://juejin.cn/post/69601302052266311754 本文解决的问题 本文主要使用 MediaCodec 硬编码器对 Android 设备采集的音视频编码 ...
- MediaCodec 编码时间戳问题
在MediaCodec 的编码时候,需要调用queueInputBuffer( int index, int offset, int size, long presentationTimeUs, in ...
- YUV通过MediaCodec编码H264
Camear_MainActivity.java,主界面类 import android.app.Activity; import android.graphics.ImageFormat; impo ...
- 从原理到实践:使用Mediacodec编码H265并实现解码H265码流
H265 H265,也称为HEVC(High Efficiency Video Coding),是一种高效视频编码格式.它是H264(AVC)的后继者,也是ITU-T和ISO/IEC联合开发的标准.相 ...
- Android MediaCodec 编码使用介绍
想要了解安卓的编解码,首先要从api的使用开始,下面介绍一下使用MediaCodec的使用流程. Java层API使用介绍 编码篇: 1.获取编解码器信息 首先我们需要获取Codec的信息,通过Med ...
- Android用MediaCodec将相机预览帧编码成MP4视频
文章目录 知识预备 实现思路 获取图像数据帧 编码视频 初始化编码器 编码转换 编码视频 问题记录 最近项目中,有一个在扫码同时录视频的需求.扫码框架是通过摄像头 onPreviewFrame方法获取 ...
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式 最近在研究EasyDarwin的Push库EasyPusher,EasyPusher可以推送H264视频到 ...
最新文章
- Cookie和Session-学习笔记03【Session快速入门、Session细节】
- Teams Bot开发系列:Bot验证
- 我从参加#PerfMatters会议中学到的东西
- oracle13001,安装oracle11g 遇到INS-13001环境不知足最低要求 解决方法
- 跨平台的报表生成器控件Stimulsoft Reports.Fx for Flex
- python 并行_python并行处理任务时 该用多进程?还是该用多线程?
- AndroidTelephony学习大纲
- 00 后的 AI 开发者进阶之道:从入门到鏖战 MIT 编程大赛 | 人物志
- 浅谈输入阻抗、输出阻抗和阻抗匹配
- python 卡方检验 特征选择_特征选择:卡方检验
- 论文阅读:Neural Motifs: Scene Graph Parsing with Global Context
- 解决The following packages have unmet dependencies问题!!!
- java实现生成水印照片
- 局域网SDN技术硬核内幕 二 云网CP的日常恩爱——硬件VXLAN转发平面
- docker容器 如何精简镜像减小体积
- python名片管理器实验报告_名片管理系统——实验报告.doc
- if else python格式_python 基本的if_else使用
- [neovim/nvim] LSP 与代码补全配置笔记
- 超级高铁原型机现身迪拜,时速高达1200公里!
- 超级轻量级: KV存储引擎实现