• Android端WebRTC启用H264编码


    Android端WebRTC启用H264编码

    目前Android的使用WebRTC仅支持硬件上 H.264 解码和编码,并且仅支持部分芯片组。因此,如果设备不支持硬件 H.264 或具有不受支持的芯片组,您将只能使用 VP8、VP9。支持的芯片组仅有OMX.qcom.OMX.Exynos.**,不支持的要自行添加。

    这里也是在createOffersdp中没有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() {
    	// Android19以下不支持硬解编码.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            return new VideoCodecInfo[0];
        }
    
        List<VideoCodecInfo> supportedCodecInfos = new ArrayList<>();
        // 按优先顺序生成支持的编解码器列表:
        // VP8, VP9, H264 (high profile), and H264 (baseline profile).
        for (VideoCodecType type : new VideoCodecType[]{VideoCodecType.VP8, VideoCodecType.VP9, VideoCodecType.H264}) {
    		//查找编解码器类型,这里是关键
    		MediaCodecInfo codec = findCodecForType(type);
    		if (codec != null) {
    			String name = type.name();
                // supported by the decoder.
                if (type == VideoCodecType.H264 && isH264HighProfileSupported(codec)) {
                    supportedCodecInfos.add(new VideoCodecInfo(
                                name, MediaCodecUtils.getCodecProperties(type, /* highProfile= */ true)));
                }
    			supportedCodecInfos.add(new VideoCodecInfo(
                            name, MediaCodecUtils.getCodecProperties(type, /* highProfile= */ 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);
            }
            //编解器信息为null,或者不是编解码器不是编码器
    		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;
    	}
    	// Check for a supported color format.
    	if (MediaCodecUtils.selectColorFormat(
                    MediaCodecUtils.ENCODER_COLOR_FORMATS, /*这一步其实就可以判断编解码器是否支持了给定的类型了,如果不抛异常的话*/info.getCapabilitiesForType(type.mimeType()))
                    == null) {
    		return false;
    	}
    	return isHardwareSupportedInCurrentSdk(info, type) && isMediaCodecAllowed(info);
    }
    
    /**
     * 结合当前的sdk,再次判断是否支持
     */
    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) {
    	//H264 硬件在此类型设备上可能表现不佳。"SAMSUNG-SGH-I337", "Nexus 7", "Nexus 4"
    	if (H264_HW_EXCEPTION_MODELS.contains(Build.MODEL)) {
    		return false;
    	} else {
    		String name = info.getName();
    		//问题就在这,写死的仅支持的硬件编码器解码器组件名称的前缀。
    		//所以要在后面自行追加我们自己设备支持H264名称信息。
    		return name.startsWith("OMX.qcom.") && VERSION.SDK_INT >= 19 || name.startsWith("OMX.Exynos.") && VERSION.SDK_INT >= 21;
    	}
    }
    

    至此,分析流程结束,如有错误或其它更好的方法,欢迎指正。

    Github传送门

  • 相关阅读:
    Enum枚举类型实战总结,保证有用!
    grep 文本搜索工具
    awk 文本编辑器
    sed 流编辑器
    shell 里使用 sed awk
    crontab
    mysqlbinlog日志
    ZK简介,部署
    curl
    正则表达式
  • 原文地址:https://www.cnblogs.com/qq714081644/p/15267531.html
Copyright © 2020-2023  润新知