不复现闪退问题
- 编码时间戳问题
E/MPEG4Writer: do not support out of order frames (timestamp: 2275555 < last: 2275618 for Audio track
问题发生在多个视频拼接时,上个素材的最后一次writeSampleData和下个素材的第一次writeSampleData的时间戳被设置为相等,设置一个时间偏移(200)即解决问题。
- OOM问题
不复现闪退问题盲猜大多数都是OOM问题。
做音视频一段时间后,OOM问题增多,需要治理。但是治理起来是个系统工程,我有另外的性能优化工程“黄金眼”要做,此处暂不展开。
QA已经提bug了,暂时如何解决呢?
(1)在视频合成时,停止并释放播放器。视频合成过程我抽去了一个单独的activity页面。
(2)针对log报错BitmapFactory.decodeFile处发生的OOM,对图片进行压缩。
(3)在AndroidManifest中增加configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout",使折叠屏切换折叠态时不要Activity不要重建
(4)...
各种兼容不适问题
- 某华为nova机型视频+音乐合成出来的视频没有音乐
原因是一般情况下音视频合并时,先获取到音频轨道信息,再获取到视频轨道信息,在添加视频轨道时启动合成器。但是该机型却先添加了视频轨再添加音频轨,因为添加视频轨时已经启动了合成器,所以音频轨没有添加进去。对这种情况进行兼容,保证应有的音频轨添加之后才能开启合成器。
对MediaMuxer添加轨道代码如下:
void onSetOutputFormat() {
if (videoFormat != null && audioFormat != null && !hasAddTrack) {
videoTrackIndex = muxer.addTrack(videoFormat);
Log.v(TAG, "Added track #" + videoTrackIndex + " with " + videoFormat.getString(MediaFormat.KEY_MIME) + " to muxer");
audioTrackIndex = muxer.addTrack(audioFormat);
Log.v(TAG, "Added track #" + audioTrackIndex + " with " + audioFormat.getString(MediaFormat.KEY_MIME) + " to muxer");
hasAddTrack = true;
} else if (videoFormat != null && !hasAddTrack) {
//如果有音频但还没有获得 audioFormat ,此次等待,不启动
if (hasAudio) {
return;
}
videoTrackIndex = muxer.addTrack(videoFormat);
Log.v(TAG, "Added track #" + videoTrackIndex + " with " + videoFormat.getString(MediaFormat.KEY_MIME) + " to muxer");
hasAddTrack = true;
}else if(audioFormat!=null && !hasAddTrack){
//只有音频audioFormat,此次等待,不启动
return;
}
if (!started) {
muxer.start();
started = true;
}
其中,videoFormat和audioFormat在编码器dequeueOutputBuffer返回值为MediaCodec.INFO_OUTPUT_FORMAT_CHANGED时使用encoder.getOutputFormat()取得。
- 图片+视频合成部分机型编码错误
图片与有音轨的视频合并时,特别是第一个素材为图片的情况,图片没有音轨,视频有音轨,使用mediaMuxer合成视频时,必须在开启前设置音轨。在这种情况下,有音频的素材还没有开始解码,那么我们用一个默认的音频格式设置音轨。然后等第二个素材开始解码编码时,写入音频轨,有些机型可以成功合成,很多机型遇到音频编码错误问题。那么当有音轨和无音轨的素材混合合成时,有没有更好的办法呢?
用一段静默音频填充不就好了吗?
正解,用静默音频填充图片编码时的音轨,静默音频来源于一段2s的mp3,将其同视频原声一样进行解码和重采样。
- oppo实验室机型,视频合成失败,log报错
11-26 10:19:45.535 19551 29726 D CCodec : quality is missing, which is required for video encoders in CQ.
11-26 10:19:45.535 19551 29725 E MediaCodec: Codec reported err 0xffffffea, actionCode 0, while in state 3
这是编码器设置bitmode为常量时没有设置quality的问题。(题外话;从android R开始google开始使用CCodec框架,据平台方oppo说他们没有提供拓展CCodec的能力,当硬件编解码器报错时,应由第三方app创建软编解码器)。我的解决方法如下,quality参数需要调用api获取系统编码能力信息。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (!encoder.getName().equals("OMX.qcom.video.encoder.avc")
&& !encoder.getName().equals("OMX.hisi.video.encoder.avc")
&& !encoder.getName().equals("OMX.MTK.VIDEO.ENCODER.AVC")) {
outputFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ);
if(Mp4Composer.getInstance().getCodecInfo()==null){
Mp4Composer.getInstance().findMediaCodecInfo();
}
if(Mp4Composer.getInstance().getCodecInfo()!=null && Build.VERSION.SDK_INT >=Build.VERSION_CODES.P){
MediaCodecInfo.CodecCapabilities capabilities = Mp4Composer.getInstance().getCodecInfo().getCapabilitiesForType("video/avc");
int quality =capabilities.getEncoderCapabilities().getQualityRange().getLower();
outputFormat.setInteger(MediaFormat.KEY_QUALITY,quality);
}
}
}
4.某些oppo、vivo机型视频合成失败
原因是由于手机系统摄像头像素较高,摄像头拍摄图片尺寸过大超过视频编码支持尺寸,这种情况下的解决方法是:由于在移动端通用的高清视频一般是1080p,所以使用的视频尺寸一般在1080*1920内,限制最终合成视频最大不超过这个尺寸。超过时使用opengl矩阵等比缩放。
关于编码器支持的视频尺寸,在实践过程中发现,编码尺寸除了不能过大以外,也不能过小,还有编码器编码只支持偶数尺寸的宽高。还有,有一些比较老的手机支持的硬编码尺寸只能是8的倍数。
5.某些机型录制的视频经合成后,画面偏移90度。
定位该问题时发现,和大部分华为等手机不同,oppo手机竖屏录制视频时获得的宽高是相反的,即发现文件系统读取的宽高和mediaExtractor解析视频轨道后得到的MediaFormat中宽高参数相反。对于这种情况,可以用mediaMetadataRetriever解析出视频素材的旋转角度。然后在opengl对旋转处理过程中加上这个素材的原始旋转角度。
6.编码时间戳和相关时间偏移量,应注意用类型,若不小心用了int,容易溢出,发生各种诡异问题。