0X00 MediaCodec
1.MediaCodec 的两种编码模式:
ByteBuffer 模式:
格式:COLOR_FORMAT 对应的值是 MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar(图像格式 NV21,也可能是其他的需要一一对应)。
操作:通过 MediaCodec.dequeueInputBuffer() 获取数据输入缓冲区,再通过 MediaCodec.queueInputBuffer() 手动将 YUV 图像传给 MediaCodec。
Surface 模式:
格式:COLOR_FORMAT 对应的值是 MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface。
操作:通过 MediaCodec.createInputSurface() 创建编码数据源 Surface,再通过 OpenGL 纹理,将相机预览图像绘制到该 Surface 上。
2.MediaCodec 参数
String codecName = MediaFormat.MIMETYPE_VIDEO_AVC;
int colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar;
MediaFormat encodeMediaFormat = MediaFormat.createVideoFormat(codecName, width, height);
encodeMediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
encodeMediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2500000);
encodeMediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
encodeMediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
encodeMediaFormat.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
MediaCodec encodeCodec = MediaCodec.createByCodecName(codecName);
encodeCodec.configure(encodeMediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
encodeCodec.start();
KEY_COLOR_FORMAT, 编码前源颜色格式
KEY_BIT_RATE, 比特率越高,每秒传送数据就越多,画质就越清晰,视频文件占用空间也越大。
KEY_FRAME_RATE, 帧率,视频每秒传输的帧数(画面数),每秒帧数越多,显示的画面就越流畅,但是码率恒定帧率增加,画质则会降低。
KEY_I_FRAME_INTERVAL 关键帧间隔
android.media.MediaCodec$CodecException错误。
0x01 重点参数解释
KEY_BITRATE_MODE 模式
BITRATE_MODE_CQ
忽略用户设置的码率,由编码器自己控制码率,并尽可能保证画面清晰度和码率的均衡。
BITRATE_MODE_CBR
无论视频的画面内容如果,尽可能遵守用户设置的码率
BITRATE_MODE_VBR
尽可能遵守用户设置的码率,但是会根据帧画面之间运动矢量(通俗理解就是帧与帧之间的画面变化程度)来动态调整码率,如果运动矢量较大,则在该时间段将码率调高,如果画面变换很小,则码率降低。
KEY_COLOR_FORMAT
是因为Android的Camera预览,只支持NV21(默认)和YV12,但是MediaCodec却只支持编码成NV12和YU12,源数据却是NV21,那我们就需要先将数据转成对应的YUV再丢给编码器去编码。
ImageFormat.中可以查到
* @see android.hardware.Camera.Parameters#setPreviewCallback
* @see android.hardware.Camera.Parameters#setPreviewFormat
* @see android.hardware.Camera.Parameters#getSupportedPreviewFormats
*
*/
public static final int YV12 = 0x32315659;
* @see android.hardware.Camera.Parameters#setPreviewCallback
* @see android.hardware.Camera.Parameters#setPreviewFormat
* @see android.hardware.Camera.Parameters#getSupportedPreviewFormats
*
*/
public static final int YV12 = 0x32315659;
所以一定要保证输入的yuv格式需要跟配置的colorFormat对的上,如果对不上就需要转换成对应的YUV格式。
COLOR_FormatYUV420Planar = I420 = YV21 = 19,而COLOR_FormatYUV420SemiPlanar = NV12 = 21。
官方推荐去使用COLOR_FormatYUV420Flexible, YUV420Flexible并不是一种确定的YUV420格式,而是包含COLOR_FormatYUV411Planar, COLOR_FormatYUV411PackedPlanar, COLOR_FormatYUV420Planar, COLOR_FormatYUV420PackedPlanar, COLOR_FormatYUV420SemiPlanar和COLOR_FormatYUV420PackedSemiPlanar。
/**
* Flexible 12 bits per pixel, subsampled YUV color format with 8-bit chroma and luma
* components.
*
* Chroma planes are subsampled by 2 both horizontally and vertically.
* Use this format with {@link Image}.
* This format corresponds to {@link android.graphics.ImageFormat#YUV_420_888},
* and can represent the {@link #COLOR_FormatYUV411Planar},
* {@link #COLOR_FormatYUV411PackedPlanar}, {@link #COLOR_FormatYUV420Planar},
* {@link #COLOR_FormatYUV420PackedPlanar}, {@link #COLOR_FormatYUV420SemiPlanar}
* and {@link #COLOR_FormatYUV420PackedSemiPlanar} formats.
*
* @see Image#getFormat
*/
public static final int COLOR_FormatYUV420Flexible = 0x7F420888;
COLOR_FormatYUV420Flexible 它大体意思是,这是个通用包容的适配钥匙。
0X02 错误处理
01黑白画面
不同设备 COLOR_Format不同,可以尝试更换COLOR_FormatYUV420Flexible为其他具体的某一项(多见于MTK)。
02 level、profile设置不兼容
最安全的情况是将Profile设置为Baseline。
mFormat.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh);
mFormat.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel31);
由于视频编码后显示的数据质量偏低,所以需要调整质量。这个时候需要在这个设置level、profile
Profile是对视频压缩特性的描述(CABAC呀、颜色采样数等等)。
Level是对视频本身特性的描述(码率、分辨率、fps)。
简单来说,Profile越高,就说明采用了越高级的压缩特性。
Level越高,视频的码率、分辨率、fps越高
在android7.0以下,android 内部写死了参数,编码出来的只能是Baseline,除非系统改过这个BUG,否者设置无效,甚至会导致configure参数失败。
0x03 呼吸效应定位处理
(1)现象:
呼吸效应在静止的场景下比较容易观察出来,运动场景中,大部分的图像内容都在变化,不容易发现。
表现为整个视频流,就会周期性出现清楚到模糊的突变。
(2)原因分析:
编码产生:
由于I帧的插入造成图像质量忽然变好,切换到P帧后又忽然变差。一般情况下,我们都会将I帧调的比较大,一个GOP内,离I帧越远的P帧,编码误差越大,图像降质也越严重,当下一个I帧出现时,图像又立即变得清楚起来。
产生的主要原因:I帧和P帧的编码模式和编码质量的不同,导致视觉上图像不连续。
物理镜头原因:
焦距就会发生变化,长对焦行程的定焦镜头或者变焦镜头容易出现这个问题
(3)解决方案:
编码产生:
重新调节 gop组大小和码率 帧率,保证I帧和P帧大小不要相差太大(保证编码质量稳定)。
镜头原因(不过多讨论)
1、调整焦距,2、采用像方远心设计。
0X04拖尾效应 处理
(1)现象:
动态画面似乎不连贯,运动不够流畅,运动影像后面总有一部分拖尾的现象。
(2)原因分析:
拍摄快速运动的对象时,画面帧率不足造成的。
(3)解决方案:
增加帧率和码率。
0X05 其他处理
生成视频增加位置坐标属性,mediaMuxer有提供api 实现。
if (mediaMuxer != null) {
mediaMuxer.setLocation(latitude, longitude);
}