Support H.264 high profile encoding on Exynos devices.
Guarded by field trial - similar to high profile encoder. If high profile is requested, but device do not support it then fallback to baseline profile. BUG=b/34816463 Review-Url: https://codereview.webrtc.org/2936313002 Cr-Commit-Position: refs/heads/master@{#18619}
This commit is contained in:
@ -70,6 +70,7 @@ public class MediaCodecVideoEncoder {
|
|||||||
private MediaCodec mediaCodec;
|
private MediaCodec mediaCodec;
|
||||||
private ByteBuffer[] outputBuffers;
|
private ByteBuffer[] outputBuffers;
|
||||||
private EglBase14 eglBase;
|
private EglBase14 eglBase;
|
||||||
|
private int profile;
|
||||||
private int width;
|
private int width;
|
||||||
private int height;
|
private int height;
|
||||||
private Surface inputSurface;
|
private Surface inputSurface;
|
||||||
@ -79,6 +80,9 @@ public class MediaCodecVideoEncoder {
|
|||||||
private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9";
|
private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9";
|
||||||
private static final String H264_MIME_TYPE = "video/avc";
|
private static final String H264_MIME_TYPE = "video/avc";
|
||||||
|
|
||||||
|
private static final int VIDEO_AVCProfileHigh = 8;
|
||||||
|
private static final int VIDEO_AVCLevel3 = 0x100;
|
||||||
|
|
||||||
// Type of bitrate adjustment for video encoder.
|
// Type of bitrate adjustment for video encoder.
|
||||||
public enum BitrateAdjustmentType {
|
public enum BitrateAdjustmentType {
|
||||||
// No adjustment - video encoder has no known bitrate problem.
|
// No adjustment - video encoder has no known bitrate problem.
|
||||||
@ -92,6 +96,25 @@ public class MediaCodecVideoEncoder {
|
|||||||
DYNAMIC_ADJUSTMENT
|
DYNAMIC_ADJUSTMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be in sync with webrtc::H264::Profile.
|
||||||
|
public static enum H264Profile {
|
||||||
|
CONSTRAINED_BASELINE(0),
|
||||||
|
BASELINE(1),
|
||||||
|
MAIN(2),
|
||||||
|
CONSTRAINED_HIGH(3),
|
||||||
|
HIGH(4);
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
H264Profile(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Class describing supported media codec properties.
|
// Class describing supported media codec properties.
|
||||||
private static class MediaCodecProperties {
|
private static class MediaCodecProperties {
|
||||||
public final String codecPrefix;
|
public final String codecPrefix;
|
||||||
@ -143,6 +166,13 @@ public class MediaCodecVideoEncoder {
|
|||||||
private static final MediaCodecProperties[] h264HwList =
|
private static final MediaCodecProperties[] h264HwList =
|
||||||
new MediaCodecProperties[] {qcomH264HwProperties, exynosH264HwProperties};
|
new MediaCodecProperties[] {qcomH264HwProperties, exynosH264HwProperties};
|
||||||
|
|
||||||
|
// List of supported HW H.264 high profile encoders.
|
||||||
|
private static final MediaCodecProperties exynosH264HighProfileHwProperties =
|
||||||
|
new MediaCodecProperties(
|
||||||
|
"OMX.Exynos.", Build.VERSION_CODES.M, BitrateAdjustmentType.FRAMERATE_ADJUSTMENT);
|
||||||
|
private static final MediaCodecProperties[] h264HighProfileHwList =
|
||||||
|
new MediaCodecProperties[] {exynosH264HighProfileHwProperties};
|
||||||
|
|
||||||
// List of devices with poor H.264 encoder quality.
|
// List of devices with poor H.264 encoder quality.
|
||||||
// HW H.264 encoder on below devices has poor bitrate control - actual
|
// HW H.264 encoder on below devices has poor bitrate control - actual
|
||||||
// bitrates deviates a lot from the target value.
|
// bitrates deviates a lot from the target value.
|
||||||
@ -234,6 +264,11 @@ public class MediaCodecVideoEncoder {
|
|||||||
&& (findHwEncoder(H264_MIME_TYPE, h264HwList, supportedColorList) != null);
|
&& (findHwEncoder(H264_MIME_TYPE, h264HwList, supportedColorList) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isH264HighProfileHwSupported() {
|
||||||
|
return !hwEncoderDisabledTypes.contains(H264_MIME_TYPE)
|
||||||
|
&& (findHwEncoder(H264_MIME_TYPE, h264HighProfileHwList, supportedColorList) != null);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isVp8HwSupportedUsingTextures() {
|
public static boolean isVp8HwSupportedUsingTextures() {
|
||||||
return !hwEncoderDisabledTypes.contains(VP8_MIME_TYPE)
|
return !hwEncoderDisabledTypes.contains(VP8_MIME_TYPE)
|
||||||
&& (findHwEncoder(VP8_MIME_TYPE, vp8HwList(), supportedSurfaceColorList) != null);
|
&& (findHwEncoder(VP8_MIME_TYPE, vp8HwList(), supportedSurfaceColorList) != null);
|
||||||
@ -380,12 +415,14 @@ public class MediaCodecVideoEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean initEncode(VideoCodecType type, int width, int height, int kbps, int fps,
|
boolean initEncode(VideoCodecType type, int profile, int width, int height, int kbps, int fps,
|
||||||
EglBase14.Context sharedContext) {
|
EglBase14.Context sharedContext) {
|
||||||
final boolean useSurface = sharedContext != null;
|
final boolean useSurface = sharedContext != null;
|
||||||
Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height + ". @ " + kbps
|
Logging.d(TAG,
|
||||||
+ " kbps. Fps: " + fps + ". Encode from texture : " + useSurface);
|
"Java initEncode: " + type + ". Profile: " + profile + " : " + width + " x " + height
|
||||||
|
+ ". @ " + kbps + " kbps. Fps: " + fps + ". Encode from texture : " + useSurface);
|
||||||
|
|
||||||
|
this.profile = profile;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
if (mediaCodecThread != null) {
|
if (mediaCodecThread != null) {
|
||||||
@ -394,6 +431,7 @@ public class MediaCodecVideoEncoder {
|
|||||||
EncoderProperties properties = null;
|
EncoderProperties properties = null;
|
||||||
String mime = null;
|
String mime = null;
|
||||||
int keyFrameIntervalSec = 0;
|
int keyFrameIntervalSec = 0;
|
||||||
|
boolean configureH264HighProfile = false;
|
||||||
if (type == VideoCodecType.VIDEO_CODEC_VP8) {
|
if (type == VideoCodecType.VIDEO_CODEC_VP8) {
|
||||||
mime = VP8_MIME_TYPE;
|
mime = VP8_MIME_TYPE;
|
||||||
properties = findHwEncoder(
|
properties = findHwEncoder(
|
||||||
@ -408,6 +446,16 @@ public class MediaCodecVideoEncoder {
|
|||||||
mime = H264_MIME_TYPE;
|
mime = H264_MIME_TYPE;
|
||||||
properties = findHwEncoder(
|
properties = findHwEncoder(
|
||||||
H264_MIME_TYPE, h264HwList, useSurface ? supportedSurfaceColorList : supportedColorList);
|
H264_MIME_TYPE, h264HwList, useSurface ? supportedSurfaceColorList : supportedColorList);
|
||||||
|
if (profile == H264Profile.CONSTRAINED_HIGH.getValue()) {
|
||||||
|
EncoderProperties h264HighProfileProperties = findHwEncoder(H264_MIME_TYPE,
|
||||||
|
h264HighProfileHwList, useSurface ? supportedSurfaceColorList : supportedColorList);
|
||||||
|
if (h264HighProfileProperties != null) {
|
||||||
|
Logging.d(TAG, "High profile H.264 encoder supported.");
|
||||||
|
configureH264HighProfile = true;
|
||||||
|
} else {
|
||||||
|
Logging.d(TAG, "High profile H.264 encoder requested, but not supported. Use baseline.");
|
||||||
|
}
|
||||||
|
}
|
||||||
keyFrameIntervalSec = 20;
|
keyFrameIntervalSec = 20;
|
||||||
}
|
}
|
||||||
if (properties == null) {
|
if (properties == null) {
|
||||||
@ -453,6 +501,10 @@ public class MediaCodecVideoEncoder {
|
|||||||
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
|
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
|
||||||
format.setInteger(MediaFormat.KEY_FRAME_RATE, targetFps);
|
format.setInteger(MediaFormat.KEY_FRAME_RATE, targetFps);
|
||||||
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
|
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
|
||||||
|
if (configureH264HighProfile) {
|
||||||
|
format.setInteger("profile", VIDEO_AVCProfileHigh);
|
||||||
|
format.setInteger("level", VIDEO_AVCLevel3);
|
||||||
|
}
|
||||||
Logging.d(TAG, " Format: " + format);
|
Logging.d(TAG, " Format: " + format);
|
||||||
mediaCodec = createByCodecName(properties.codecName);
|
mediaCodec = createByCodecName(properties.codecName);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@ -711,6 +763,12 @@ public class MediaCodecVideoEncoder {
|
|||||||
outputBuffers[result].position(info.offset);
|
outputBuffers[result].position(info.offset);
|
||||||
outputBuffers[result].limit(info.offset + info.size);
|
outputBuffers[result].limit(info.offset + info.size);
|
||||||
configData.put(outputBuffers[result]);
|
configData.put(outputBuffers[result]);
|
||||||
|
// Log few SPS header bytes to check profile and level.
|
||||||
|
String spsData = "";
|
||||||
|
for (int i = 0; i < (info.size < 8 ? info.size : 8); i++) {
|
||||||
|
spsData += Integer.toHexString(configData.get(i) & 0xff) + " ";
|
||||||
|
}
|
||||||
|
Logging.d(TAG, spsData);
|
||||||
// Release buffer back.
|
// Release buffer back.
|
||||||
mediaCodec.releaseOutputBuffer(result, false);
|
mediaCodec.releaseOutputBuffer(result, false);
|
||||||
// Query next output.
|
// Query next output.
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import org.webrtc.MediaCodecVideoEncoder.OutputBufferInfo;
|
|||||||
@RunWith(BaseJUnit4ClassRunner.class)
|
@RunWith(BaseJUnit4ClassRunner.class)
|
||||||
public class MediaCodecVideoEncoderTest {
|
public class MediaCodecVideoEncoderTest {
|
||||||
final static String TAG = "MediaCodecVideoEncoderTest";
|
final static String TAG = "MediaCodecVideoEncoderTest";
|
||||||
|
final static int profile = MediaCodecVideoEncoder.H264Profile.CONSTRAINED_BASELINE.getValue();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@ -40,7 +41,7 @@ public class MediaCodecVideoEncoderTest {
|
|||||||
}
|
}
|
||||||
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
||||||
assertTrue(encoder.initEncode(
|
assertTrue(encoder.initEncode(
|
||||||
MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480, 300, 30, null));
|
MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile, 640, 480, 300, 30, null));
|
||||||
encoder.release();
|
encoder.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,8 +54,8 @@ public class MediaCodecVideoEncoderTest {
|
|||||||
}
|
}
|
||||||
EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
|
EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
|
||||||
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
||||||
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480,
|
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
|
||||||
300, 30, eglBase.getEglBaseContext()));
|
640, 480, 300, 30, eglBase.getEglBaseContext()));
|
||||||
encoder.release();
|
encoder.release();
|
||||||
eglBase.release();
|
eglBase.release();
|
||||||
}
|
}
|
||||||
@ -68,11 +69,11 @@ public class MediaCodecVideoEncoderTest {
|
|||||||
}
|
}
|
||||||
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
||||||
assertTrue(encoder.initEncode(
|
assertTrue(encoder.initEncode(
|
||||||
MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480, 300, 30, null));
|
MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile, 640, 480, 300, 30, null));
|
||||||
encoder.release();
|
encoder.release();
|
||||||
EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
|
EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
|
||||||
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, 640, 480,
|
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
|
||||||
300, 30, eglBase.getEglBaseContext()));
|
640, 480, 300, 30, eglBase.getEglBaseContext()));
|
||||||
encoder.release();
|
encoder.release();
|
||||||
eglBase.release();
|
eglBase.release();
|
||||||
}
|
}
|
||||||
@ -92,8 +93,8 @@ public class MediaCodecVideoEncoderTest {
|
|||||||
|
|
||||||
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
||||||
|
|
||||||
assertTrue(encoder.initEncode(
|
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
|
||||||
MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, width, height, 300, 30, null));
|
width, height, 300, 30, null));
|
||||||
ByteBuffer[] inputBuffers = encoder.getInputBuffers();
|
ByteBuffer[] inputBuffers = encoder.getInputBuffers();
|
||||||
assertNotNull(inputBuffers);
|
assertNotNull(inputBuffers);
|
||||||
assertTrue(min_size <= inputBuffers[0].capacity());
|
assertTrue(min_size <= inputBuffers[0].capacity());
|
||||||
@ -144,8 +145,8 @@ public class MediaCodecVideoEncoderTest {
|
|||||||
|
|
||||||
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
|
||||||
|
|
||||||
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, width,
|
assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
|
||||||
height, 300, 30, eglOesBase.getEglBaseContext()));
|
width, height, 300, 30, eglOesBase.getEglBaseContext()));
|
||||||
assertTrue(
|
assertTrue(
|
||||||
encoder.encodeTexture(true, oesTextureId, RendererCommon.identityMatrix(), presentationTs));
|
encoder.encodeTexture(true, oesTextureId, RendererCommon.identityMatrix(), presentationTs));
|
||||||
GlUtil.checkNoGLES2Error("encodeTexture");
|
GlUtil.checkNoGLES2Error("encodeTexture");
|
||||||
|
|||||||
@ -274,6 +274,7 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder {
|
|||||||
// value and the next Encode() call being ignored.
|
// value and the next Encode() call being ignored.
|
||||||
bool drop_next_input_frame_;
|
bool drop_next_input_frame_;
|
||||||
bool scale_;
|
bool scale_;
|
||||||
|
webrtc::H264::Profile profile_;
|
||||||
// Global references; must be deleted in Release().
|
// Global references; must be deleted in Release().
|
||||||
std::vector<jobject> input_buffers_;
|
std::vector<jobject> input_buffers_;
|
||||||
webrtc::H264BitstreamParser h264_bitstream_parser_;
|
webrtc::H264BitstreamParser h264_bitstream_parser_;
|
||||||
@ -335,12 +336,10 @@ MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni,
|
|||||||
|
|
||||||
jclass j_output_buffer_info_class =
|
jclass j_output_buffer_info_class =
|
||||||
FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
|
FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
|
||||||
j_init_encode_method_ = GetMethodID(
|
j_init_encode_method_ =
|
||||||
jni,
|
GetMethodID(jni, *j_media_codec_video_encoder_class_, "initEncode",
|
||||||
*j_media_codec_video_encoder_class_,
|
"(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;"
|
||||||
"initEncode",
|
"IIIIILorg/webrtc/EglBase14$Context;)Z");
|
||||||
"(Lorg/webrtc/MediaCodecVideoEncoder$VideoCodecType;"
|
|
||||||
"IIIILorg/webrtc/EglBase14$Context;)Z");
|
|
||||||
j_get_input_buffers_method_ = GetMethodID(
|
j_get_input_buffers_method_ = GetMethodID(
|
||||||
jni,
|
jni,
|
||||||
*j_media_codec_video_encoder_class_,
|
*j_media_codec_video_encoder_class_,
|
||||||
@ -419,6 +418,16 @@ int32_t MediaCodecVideoEncoder::InitEncode(
|
|||||||
ALOGD << "InitEncode request: " << init_width << " x " << init_height;
|
ALOGD << "InitEncode request: " << init_width << " x " << init_height;
|
||||||
ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled");
|
ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
// Check allowed H.264 profile
|
||||||
|
profile_ = webrtc::H264::Profile::kProfileBaseline;
|
||||||
|
if (codec_type == kVideoCodecH264) {
|
||||||
|
const rtc::Optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
||||||
|
webrtc::H264::ParseSdpProfileLevelId(codec_.params);
|
||||||
|
RTC_DCHECK(profile_level_id);
|
||||||
|
profile_ = profile_level_id->profile;
|
||||||
|
ALOGD << "H.264 profile: " << profile_;
|
||||||
|
}
|
||||||
|
|
||||||
return InitEncodeInternal(
|
return InitEncodeInternal(
|
||||||
init_width, init_height, codec_settings->startBitrate,
|
init_width, init_height, codec_settings->startBitrate,
|
||||||
codec_settings->maxFramerate, codec_settings->expect_encode_from_texture);
|
codec_settings->maxFramerate, codec_settings->expect_encode_from_texture);
|
||||||
@ -531,7 +540,7 @@ int32_t MediaCodecVideoEncoder::InitEncodeInternal(int width,
|
|||||||
const VideoCodecType codec_type = GetCodecType();
|
const VideoCodecType codec_type = GetCodecType();
|
||||||
ALOGD << "InitEncodeInternal Type: " << static_cast<int>(codec_type) << ", "
|
ALOGD << "InitEncodeInternal Type: " << static_cast<int>(codec_type) << ", "
|
||||||
<< width << " x " << height << ". Bitrate: " << kbps
|
<< width << " x " << height << ". Bitrate: " << kbps
|
||||||
<< " kbps. Fps: " << fps;
|
<< " kbps. Fps: " << fps << ". Profile: " << profile_ << ".";
|
||||||
if (kbps == 0) {
|
if (kbps == 0) {
|
||||||
kbps = last_set_bitrate_kbps_;
|
kbps = last_set_bitrate_kbps_;
|
||||||
}
|
}
|
||||||
@ -570,8 +579,8 @@ int32_t MediaCodecVideoEncoder::InitEncodeInternal(int width,
|
|||||||
jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
|
jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
|
||||||
jni, "MediaCodecVideoEncoder$VideoCodecType", codec_type);
|
jni, "MediaCodecVideoEncoder$VideoCodecType", codec_type);
|
||||||
const bool encode_status = jni->CallBooleanMethod(
|
const bool encode_status = jni->CallBooleanMethod(
|
||||||
*j_media_codec_video_encoder_, j_init_encode_method_,
|
*j_media_codec_video_encoder_, j_init_encode_method_, j_video_codec_enum,
|
||||||
j_video_codec_enum, width, height, kbps, fps,
|
profile_, width, height, kbps, fps,
|
||||||
(use_surface ? egl_context_ : nullptr));
|
(use_surface ? egl_context_ : nullptr));
|
||||||
if (!encode_status) {
|
if (!encode_status) {
|
||||||
ALOGE << "Failed to configure encoder.";
|
ALOGE << "Failed to configure encoder.";
|
||||||
@ -1252,7 +1261,7 @@ MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory()
|
|||||||
CHECK_EXCEPTION(jni);
|
CHECK_EXCEPTION(jni);
|
||||||
if (is_vp8_hw_supported) {
|
if (is_vp8_hw_supported) {
|
||||||
ALOGD << "VP8 HW Encoder supported.";
|
ALOGD << "VP8 HW Encoder supported.";
|
||||||
supported_codecs_.push_back(cricket::VideoCodec("VP8"));
|
supported_codecs_.push_back(cricket::VideoCodec(cricket::kVp8CodecName));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
|
bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
|
||||||
@ -1261,7 +1270,7 @@ MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory()
|
|||||||
CHECK_EXCEPTION(jni);
|
CHECK_EXCEPTION(jni);
|
||||||
if (is_vp9_hw_supported) {
|
if (is_vp9_hw_supported) {
|
||||||
ALOGD << "VP9 HW Encoder supported.";
|
ALOGD << "VP9 HW Encoder supported.";
|
||||||
supported_codecs_.push_back(cricket::VideoCodec("VP9"));
|
supported_codecs_.push_back(cricket::VideoCodec(cricket::kVp9CodecName));
|
||||||
}
|
}
|
||||||
supported_codecs_with_h264_hp_ = supported_codecs_;
|
supported_codecs_with_h264_hp_ = supported_codecs_;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user