https://www.jianshu.com/p/175d1e4ffaad
在做视频录制时,发现使用MediaCodec做硬解码时,即使设置了MediaFormat的MediaFormat.KEY_I_FRAME_INTERVAL属性也无法控制输出Buffer中关键帧的输出数量。
后来发现原来是真正的原因是在于视频的输入源,如果是通过Camera的PreviewCallback的方式来获取视频数据再喂给MediaCodec的方式是无法控制输出关键帧的数量的。
想要控制输出输出关键帧数量就必须通过调用MediaCodec.createInputSurface()方法获取输入Surface,再通过Opengl渲染后喂给MediaCodec才能真正控制关键帧的数量(至于为什么会这样我也没搞明白,希望有明白的能指教一下)。
判断输出数据是否为关键帧的方法:
boolean keyFrame = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0;
作者:小木桨
链接:https://www.jianshu.com/p/175d1e4ffaad
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
-1 down vote
you should set KEY_I_FRAME_INTERVAL to 1 which means one key frame per KEY_FRAME_RATE.
http://blog.sina.com.cn/s/blog_79d919a70102vxqd.html
MediaCodec使用经验总结
(2015-09-21 19:02:13)
标签: androidmediacodec | 分类: Android开发 |
前提:使用Surface作为Codec的input,bytebuffer作为Codec的output。
多媒体的编码分为硬编码还是软编码。硬编码就会涉及到硬件,所以当机器不同,可能会有的机器能编码,有的机器就会编码失败。这里的MediaCodec就属于硬编码。
下面是代码的基本逻辑结构:
//创建对应格式的编码器(注意:不要把Encode和Decode混了)
m_MediaCodec = MediaCodec.createEncoderByType("video/avc");
//创建一个Format用来设置Codec的格式
m_MediaFormat = MediaFormat.createVideoFormat("video/avc", 480, 800);
//码流
m_MediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2500000);
//帧数
m_MediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 32);
//颜色格式
m_MediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
//关键帧
m_MediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
//配置Codec
m_MediaCodec.configure(m_MediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//获取Surface作为input,这句必须放在configure()之后,start()之前。
m_Surface = m_MediaCodec.createInputSurface();
//启动Codec
m_MediaCodec.start();
//编码部分
m_BufferInfo = new MediaCodec.BufferInfo();
//尝试获取输出数据的信息,关于bytebuffer的信息将封装在bufferinfo里面,返回该bytebuffer在队列中的位置
int index = m_MediaCodec.dequeueOutputBuffer(m_BufferInfo, 0);
while(isEncode){
if (index >= 0) {
//取出编码成功的bytebuffer
ByteBuffer outPutByteBuffer = m_MediaCodec.getOutputBuffer(index);
//将bytebuffer内的数据放入byte数组中
byte[] outDate = new byte[m_BufferInfo.size];
outPutByteBuffer.get(outDate);
//将编码后的数据写入文件或者做其他处理
m_FileOutputStream.write(outDate);
//释放刚刚从Codec取出数据的bytebuffer,供Codec继续放数据。
m_MediaCodec.releaseOutputBuffer(index, false);
//再尝试从Codec中获取输出数据的信息
index = m_MediaCodec.dequeueOutputBuffer(m_BufferInfo, 0);
}else{
index = m_MediaCodec.dequeueOutputBuffer(m_BufferInfo, 0);
continue;
}
}
这里有一点需要说明,Codec并不是只要一start就会有数据输出,也不会只要有数据输出就会不断的输出。
如下图Log输出index值:
另外,因为Surface作为input的时候不会主动向Codec传递结束标志,所以得手动调用m_MediaCodec.signalEndOfInputStream();
这时Surface将停止向Codec传输数据。注意此函数只有当Surface作为input时才能调用。
结束编码记得release和stop