Android端WebRTC启用H264编码
目前Android的使用WebRTC仅支持硬件上 H.264 解码和编码,并且仅支持部分芯片组。因此,如果设备不支持硬件 H.264 或具有不受支持的芯片组,您将只能使用 VP8、VP9。支持的芯片组仅有OMX.qcom.*和OMX.Exynos.*,不支持的要自行添加。
这里也是在createOffer后sdp中没有H264信息的原因
VideoEncoderFactory创建
在创建PeerConnectionFactory,可以设VideoEncoderFactory
val encoderFactory = DefaultVideoEncoderFactory(eglBaseContext, true, true)
val peerConnectionFactory = PeerConnectionFactory.builder()
.setVideoEncoderFactory(encoderFactory)
.createPeerConnectionFactory()
DefaultVideoEncoderFactory类
public class DefaultVideoEncoderFactory implements VideoEncoderFactory {
private final VideoEncoderFactory hardwareVideoEncoderFactory;
private final VideoEncoderFactory softwareVideoEncoderFactory = new SoftwareVideoEncoderFactory();
public DefaultVideoEncoderFactory(Context eglContext, boolean enableIntelVp8Encoder, boolean enableH264HighProfile) {
this.hardwareVideoEncoderFactory = new HardwareVideoEncoderFactory(eglContext, enableIntelVp8Encoder, enableH264HighProfile);
}
DefaultVideoEncoderFactory(VideoEncoderFactory hardwareVideoEncoderFactory) {
this.hardwareVideoEncoderFactory = hardwareVideoEncoderFactory;
}
...
}
DefaultVideoEncoderFactory、HardwareVideoEncoderFactory、SoftwareVideoEncoderFactory类均实现了VideoEncoderFactory接口
VideoEncoderFactory
public interface VideoEncoderFactory {
@Nullable
@CalledByNative
VideoEncoder createEncoder(VideoCodecInfo var1);
@CalledByNative
VideoCodecInfo[] getSupportedCodecs();
@CalledByNative
default VideoCodecInfo[] getImplementations() {
return this.getSupportedCodecs();
}
@CalledByNative
default VideoEncoderFactory.VideoEncoderSelector getEncoderSelector() {
return null;
}
}
关键在于getSupportedCodecs() 在 HardwareVideoEncoderFactory中是如何实现的?
@Override
public VideoCodecInfo[] getSupportedCodecs() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return new VideoCodecInfo[0];
}
List<VideoCodecInfo> supportedCodecInfos = new ArrayList<>();
for (VideoCodecType type : new VideoCodecType[]{VideoCodecType.VP8, VideoCodecType.VP9, VideoCodecType.H264}) {
MediaCodecInfo codec = findCodecForType(type);
if (codec != null) {
String name = type.name();
if (type == VideoCodecType.H264 && isH264HighProfileSupported(codec)) {
supportedCodecInfos.add(new VideoCodecInfo(
name, MediaCodecUtils.getCodecProperties(type, true)));
}
supportedCodecInfos.add(new VideoCodecInfo(
name, MediaCodecUtils.getCodecProperties(type, false)));
}
}
return supportedCodecInfos.toArray(new VideoCodecInfo[0]);
}
findCodecForType(VideoCodecType),根据类型查找支持的编解码器
private MediaCodecInfo findCodecForType(VideoCodecType type) {
for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
MediaCodecInfo info = null;
try {
info = MediaCodecList.getCodecInfoAt(i);
} catch (IllegalArgumentException e) {
Logging.e(TAG, "Cannot retrieve encoder codec info", e);
}
if (info == null || !info.isEncoder()) {
continue;
}
if (isSupportedCodec(info, type)) {
return info;
}
}
return null;
}
isSupportedCodec(MediaCodecInfo, VideoCodecType):判断MediaCodecInfo和VideoCodecType结合设备芯片组信息是否支持
private boolean isSupportedCodec(MediaCodecInfo info, VideoCodecType type) {
if (!MediaCodecUtils.codecSupportsType(info, type)) {
return false;
}
if (MediaCodecUtils.selectColorFormat(
MediaCodecUtils.ENCODER_COLOR_FORMATS, info.getCapabilitiesForType(type.mimeType()))
== null) {
return false;
}
return isHardwareSupportedInCurrentSdk(info, type) && isMediaCodecAllowed(info);
}
private boolean isHardwareSupportedInCurrentSdk(MediaCodecInfo info, VideoCodecType type) {
switch (type) {
case VP8:
return isHardwareSupportedInCurrentSdkVp8(info);
case VP9:
return isHardwareSupportedInCurrentSdkVp9(info);
case H264:
return isHardwareSupportedInCurrentSdkH264(info);
}
return false;
}
private boolean isHardwareSupportedInCurrentSdkH264(MediaCodecInfo info) {
if (H264_HW_EXCEPTION_MODELS.contains(Build.MODEL)) {
return false;
} else {
String name = info.getName();
return name.startsWith("OMX.qcom.") && VERSION.SDK_INT >= 19 || name.startsWith("OMX.Exynos.") && VERSION.SDK_INT >= 21;
}
}
至此,分析流程结束,如有错误或其它更好的方法,欢迎指正。
|