diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index edc5da30b7..9c21befd7d 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -189,6 +189,7 @@ if (is_android) { rtc_android_library("base_java") { java_files = [ "api/org/webrtc/RefCounted.java", + "api/org/webrtc/Predicate.java", "src/java/org/webrtc/CalledByNative.java", "src/java/org/webrtc/CalledByNativeUnchecked.java", "src/java/org/webrtc/Histogram.java", diff --git a/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java b/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java index 80252e642f..6907143869 100644 --- a/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java +++ b/sdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java @@ -10,10 +10,29 @@ package org.webrtc; +import android.media.MediaCodecInfo; +import java.util.Arrays; import javax.annotation.Nullable; /** Factory for Android hardware VideoDecoders. */ public class HardwareVideoDecoderFactory extends MediaCodecVideoDecoderFactory { + private final static Predicate defaultAllowedPredicate = + new Predicate() { + private String[] prefixBlacklist = + Arrays.copyOf(MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES, + MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES.length); + @Override + public boolean test(MediaCodecInfo arg) { + final String name = arg.getName(); + for (String prefix : prefixBlacklist) { + if (name.startsWith(prefix)) { + return false; + } + } + return true; + } + }; + /** Creates a HardwareVideoDecoderFactory that does not use surface textures. */ @Deprecated // Not removed yet to avoid breaking callers. public HardwareVideoDecoderFactory() { @@ -27,7 +46,21 @@ public class HardwareVideoDecoderFactory extends MediaCodecVideoDecoderFactory { * this disables texture support. */ public HardwareVideoDecoderFactory(@Nullable EglBase.Context sharedContext) { - super(sharedContext, /* prefixWhitelist= */ new String[] {""}, - /* prefixBlacklist= */ MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES); + this(sharedContext, /* codecAllowedPredicate= */ null); + } + + /** + * Creates a HardwareVideoDecoderFactory that supports surface texture rendering. + * + * @param sharedContext The textures generated will be accessible from this context. May be null, + * this disables texture support. + * @param codecAllowedPredicate predicate to filter codecs. It is combined with the default + * predicate that only allows hardware codecs. + */ + public HardwareVideoDecoderFactory(@Nullable EglBase.Context sharedContext, + @Nullable Predicate codecAllowedPredicate) { + super(sharedContext, + (codecAllowedPredicate == null ? defaultAllowedPredicate + : codecAllowedPredicate.and(defaultAllowedPredicate))); } } diff --git a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java index 4d782a968e..2f78126985 100644 --- a/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java +++ b/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java @@ -42,9 +42,34 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { @Nullable private final EglBase14.Context sharedContext; private final boolean enableIntelVp8Encoder; private final boolean enableH264HighProfile; + @Nullable private final Predicate codecAllowedPredicate; + /** + * Creates a HardwareVideoEncoderFactory that supports surface texture encoding. + * + * @param sharedContext The textures generated will be accessible from this context. May be null, + * this disables texture support. + * @param enableIntelVp8Encoder true if Intel's VP8 encoder enabled. + * @param enableH264HighProfile true if H264 High Profile enabled. + */ public HardwareVideoEncoderFactory( EglBase.Context sharedContext, boolean enableIntelVp8Encoder, boolean enableH264HighProfile) { + this(sharedContext, enableIntelVp8Encoder, enableH264HighProfile, + /* codecAllowedPredicate= */ null); + } + + /** + * Creates a HardwareVideoEncoderFactory that supports surface texture encoding. + * + * @param sharedContext The textures generated will be accessible from this context. May be null, + * this disables texture support. + * @param enableIntelVp8Encoder true if Intel's VP8 encoder enabled. + * @param enableH264HighProfile true if H264 High Profile enabled. + * @param codecAllowedPredicate optional predicate to filter codecs. All codecs are allowed + * when predicate is not provided. + */ + public HardwareVideoEncoderFactory(EglBase.Context sharedContext, boolean enableIntelVp8Encoder, + boolean enableH264HighProfile, @Nullable Predicate codecAllowedPredicate) { // Texture mode requires EglBase14. if (sharedContext instanceof EglBase14.Context) { this.sharedContext = (EglBase14.Context) sharedContext; @@ -54,6 +79,7 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { } this.enableIntelVp8Encoder = enableIntelVp8Encoder; this.enableH264HighProfile = enableH264HighProfile; + this.codecAllowedPredicate = codecAllowedPredicate; } @Deprecated @@ -164,7 +190,7 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { == null) { return false; } - return isHardwareSupportedInCurrentSdk(info, type); + return isHardwareSupportedInCurrentSdk(info, type) && isMediaCodecAllowed(info); } // Returns true if the given MediaCodecInfo indicates a hardware module that is supported on the @@ -212,6 +238,13 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory { && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); } + private boolean isMediaCodecAllowed(MediaCodecInfo info) { + if (codecAllowedPredicate == null) { + return true; + } + return codecAllowedPredicate.test(info); + } + private int getKeyFrameIntervalSec(VideoCodecType type) { switch (type) { case VP8: // Fallthrough intended. diff --git a/sdk/android/api/org/webrtc/PlatformSoftwareVideoDecoderFactory.java b/sdk/android/api/org/webrtc/PlatformSoftwareVideoDecoderFactory.java index 856db687ba..1cb52ac433 100644 --- a/sdk/android/api/org/webrtc/PlatformSoftwareVideoDecoderFactory.java +++ b/sdk/android/api/org/webrtc/PlatformSoftwareVideoDecoderFactory.java @@ -10,10 +10,33 @@ package org.webrtc; +import android.media.MediaCodecInfo; +import java.util.Arrays; import javax.annotation.Nullable; /** Factory for Android platform software VideoDecoders. */ public class PlatformSoftwareVideoDecoderFactory extends MediaCodecVideoDecoderFactory { + /** + * Default allowed predicate. + */ + private static final Predicate defaultAllowedPredicate = + new Predicate() { + private String[] prefixWhitelist = + Arrays.copyOf(MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES, + MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES.length); + + @Override + public boolean test(MediaCodecInfo arg) { + final String name = arg.getName(); + for (String prefix : prefixWhitelist) { + if (name.startsWith(prefix)) { + return true; + } + } + return false; + } + }; + /** * Creates a PlatformSoftwareVideoDecoderFactory that supports surface texture rendering. * @@ -21,7 +44,6 @@ public class PlatformSoftwareVideoDecoderFactory extends MediaCodecVideoDecoderF * this disables texture support. */ public PlatformSoftwareVideoDecoderFactory(@Nullable EglBase.Context sharedContext) { - super(sharedContext, /* prefixWhitelist= */ MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES, - /* prefixBlacklist= */ new String[] {}); + super(sharedContext, defaultAllowedPredicate); } } diff --git a/sdk/android/api/org/webrtc/Predicate.java b/sdk/android/api/org/webrtc/Predicate.java new file mode 100644 index 0000000000..50e6975000 --- /dev/null +++ b/sdk/android/api/org/webrtc/Predicate.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +/** + * Represents a predicate (boolean-valued function) of one argument. + */ +public interface Predicate { + /** + * Evaluates this predicate on the given argument. + * + * @param arg the input argument + * @return true if the input argument matches the predicate, otherwise false + */ + boolean test(T arg); + + /** + * Returns a composed predicate that represents a short-circuiting logical OR of this predicate + * and another. When evaluating the composed predicate, if this predicate is true, then the other + * predicate is not evaluated. + * + * @param other a predicate that will be logically-ORed with this predicate + * @return a composed predicate that represents the short-circuiting logical OR of this predicate + * and the other predicate + */ + default Predicate or(Predicate other) { + return new Predicate() { + @Override + public boolean test(T arg) { + return Predicate.this.test(arg) || other.test(arg); + } + }; + } + + /** + * Returns a composed predicate that represents a short-circuiting logical AND of this predicate + * and another. + * + * @param other a predicate that will be logically-ANDed with this predicate + * @return a composed predicate that represents the short-circuiting logical AND of this predicate + * and the other predicate + */ + default Predicate and(Predicate other) { + return new Predicate() { + @Override + public boolean test(T arg) { + return Predicate.this.test(arg) && other.test(arg); + } + }; + } + + /** + * Returns a predicate that represents the logical negation of this predicate. + * + * @return a predicate that represents the logical negation of this predicate + */ + default Predicate negate() { + return new Predicate() { + @Override + public boolean test(T arg) { + return !Predicate.this.test(arg); + } + }; + } +} \ No newline at end of file diff --git a/sdk/android/src/java/org/webrtc/MediaCodecVideoDecoderFactory.java b/sdk/android/src/java/org/webrtc/MediaCodecVideoDecoderFactory.java index aa272930f4..f27d700224 100644 --- a/sdk/android/src/java/org/webrtc/MediaCodecVideoDecoderFactory.java +++ b/sdk/android/src/java/org/webrtc/MediaCodecVideoDecoderFactory.java @@ -28,22 +28,20 @@ class MediaCodecVideoDecoderFactory implements VideoDecoderFactory { private static final String TAG = "MediaCodecVideoDecoderFactory"; private final @Nullable EglBase.Context sharedContext; - private final String[] prefixWhitelist; - private final String[] prefixBlacklist; + private final @Nullable Predicate codecAllowedPredicate; /** - * MediaCodecVideoDecoderFactory will support codecs whitelisted excluding those blacklisted. + * MediaCodecVideoDecoderFactory with support of codecs filtering. * * @param sharedContext The textures generated will be accessible from this context. May be null, * this disables texture support. - * @param prefixWhitelist List of codec prefixes to be whitelisted. - * @param prefixBlacklist List of codec prefixes to be blacklisted. + * @param codecAllowedPredicate optional predicate to test if codec allowed. All codecs are + * allowed when predicate is not provided. */ - public MediaCodecVideoDecoderFactory( - @Nullable EglBase.Context sharedContext, String[] prefixWhitelist, String[] prefixBlacklist) { + public MediaCodecVideoDecoderFactory(@Nullable EglBase.Context sharedContext, + @Nullable Predicate codecAllowedPredicate) { this.sharedContext = sharedContext; - this.prefixWhitelist = Arrays.copyOf(prefixWhitelist, prefixWhitelist.length); - this.prefixBlacklist = Arrays.copyOf(prefixBlacklist, prefixBlacklist.length); + this.codecAllowedPredicate = codecAllowedPredicate; } @Nullable @@ -123,25 +121,14 @@ class MediaCodecVideoDecoderFactory implements VideoDecoderFactory { == null) { return false; } - return isWhitelisted(name) && !isBlacklisted(name); + return isCodecAllowed(info); } - private boolean isWhitelisted(String name) { - for (String prefix : prefixWhitelist) { - if (name.startsWith(prefix)) { - return true; - } + private boolean isCodecAllowed(MediaCodecInfo info) { + if (codecAllowedPredicate == null) { + return true; } - return false; - } - - private boolean isBlacklisted(String name) { - for (String prefix : prefixBlacklist) { - if (name.startsWith(prefix)) { - return true; - } - } - return false; + return codecAllowedPredicate.test(info); } private boolean isH264HighProfileSupported(MediaCodecInfo info) {