mediacodec强制输出关键帧到mp4

215 篇文章 4 订阅

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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

 

https://stackoverflow.com/questions/35134253/mediacodec-mediaformat-setting-key-i-frame-interval-value-is-ignored

 

-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)

转载

标签:

android

mediacodec

分类: 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值:

MediaCodec使用经验总结
 

 

 

 

另外,因为Surface作为input的时候不会主动向Codec传递结束标志,所以得手动调用m_MediaCodec.signalEndOfInputStream();

这时Surface将停止向Codec传输数据。注意此函数只有当Surface作为input时才能调用。

结束编码记得release和stop 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值