diff --git a/webrtc/sdk/android/BUILD.gn b/webrtc/sdk/android/BUILD.gn index 8f9fb07e76..9332a15d5b 100644 --- a/webrtc/sdk/android/BUILD.gn +++ b/webrtc/sdk/android/BUILD.gn @@ -168,6 +168,7 @@ android_library("libjingle_peerconnection_java") { "api/org/webrtc/GlShader.java", "api/org/webrtc/GlTextureFrameBuffer.java", "api/org/webrtc/GlUtil.java", + "api/org/webrtc/HardwareVideoEncoderFactory.java", "api/org/webrtc/IceCandidate.java", "api/org/webrtc/MediaCodecVideoDecoder.java", "api/org/webrtc/MediaCodecVideoEncoder.java", @@ -198,6 +199,7 @@ android_library("libjingle_peerconnection_java") { "api/org/webrtc/VideoCodecStatus.java", "api/org/webrtc/VideoDecoder.java", "api/org/webrtc/VideoEncoder.java", + "api/org/webrtc/VideoEncoderFactory.java", "api/org/webrtc/VideoFileRenderer.java", "api/org/webrtc/VideoFrame.java", "api/org/webrtc/VideoRenderer.java", @@ -216,6 +218,8 @@ android_library("libjingle_peerconnection_java") { "src/java/org/webrtc/FramerateBitrateAdjuster.java", "src/java/org/webrtc/HardwareVideoEncoder.java", "src/java/org/webrtc/Histogram.java", + "src/java/org/webrtc/I420BufferImpl.java", + "src/java/org/webrtc/VideoCodecType.java", "src/java/org/webrtc/WrappedNativeI420Buffer.java", "src/java/org/webrtc/YuvConverter.java", ] @@ -247,6 +251,7 @@ if (rtc_include_tests) { "instrumentationtests/src/org/webrtc/EglRendererTest.java", "instrumentationtests/src/org/webrtc/FileVideoCapturerTest.java", "instrumentationtests/src/org/webrtc/GlRectDrawerTest.java", + "instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java", "instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java", "instrumentationtests/src/org/webrtc/NetworkMonitorTest.java", "instrumentationtests/src/org/webrtc/PeerConnectionTest.java", diff --git a/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java b/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java new file mode 100644 index 0000000000..adf16462e7 --- /dev/null +++ b/webrtc/sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.java @@ -0,0 +1,273 @@ +/* + * Copyright 2017 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; + +import android.media.MediaCodec; +import android.media.MediaCodecInfo; +import android.media.MediaCodecInfo.CodecCapabilities; +import android.media.MediaCodecList; +import android.os.Build; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Factory for android hardware video encoders. */ +@SuppressWarnings("deprecation") // API 16 requires the use of deprecated methods. +public class HardwareVideoEncoderFactory implements VideoEncoderFactory { + private static final String TAG = "HardwareVideoEncoderFactory"; + + // Prefixes for supported hardware encoder component names. + private static final String QCOM_PREFIX = "OMX.qcom."; + private static final String EXYNOS_PREFIX = "OMX.Exynos."; + private static final String INTEL_PREFIX = "OMX.Intel."; + + // Forced key frame interval - used to reduce color distortions on Qualcomm platforms. + private static final int QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_L_MS = 15000; + private static final int QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_M_MS = 20000; + private static final int QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_N_MS = 15000; + + // List of devices with poor H.264 encoder quality. + // HW H.264 encoder on below devices has poor bitrate control - actual + // bitrates deviates a lot from the target value. + private static final List H264_HW_EXCEPTION_MODELS = + Arrays.asList("SAMSUNG-SGH-I337", "Nexus 7", "Nexus 4"); + + // NV12 color format supported by QCOM codec, but not declared in MediaCodec - + // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h + private static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04; + + // Supported color formats, in order of preference. + private static final int[] SUPPORTED_COLOR_FORMATS = { + MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar, + MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar, + MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, + COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m}; + + // Keys for H264 VideoCodecInfo properties. + private static final String H264_FMTP_PROFILE_LEVEL_ID = "profile-level-id"; + private static final String H264_FMTP_LEVEL_ASYMMETRY_ALLOWED = "level-asymmetry-allowed"; + private static final String H264_FMTP_PACKETIZATION_MODE = "packetization-mode"; + + // Supported H264 profile ids and levels. + private static final String H264_PROFILE_CONSTRAINED_BASELINE = "4200"; + private static final String H264_PROFILE_CONSTRAINED_HIGH = "640c"; + private static final String H264_LEVEL_3_1 = "1f"; // 31 in hex. + private static final String H264_CONSTRAINED_BASELINE_3_1 = + H264_PROFILE_CONSTRAINED_BASELINE + H264_LEVEL_3_1; + private static final String H264_CONSTRAINED_HIGH_3_1 = + H264_PROFILE_CONSTRAINED_HIGH + H264_LEVEL_3_1; + + private final boolean enableIntelVp8Encoder; + private final boolean enableH264HighProfile; + + public HardwareVideoEncoderFactory(boolean enableIntelVp8Encoder, boolean enableH264HighProfile) { + this.enableIntelVp8Encoder = enableIntelVp8Encoder; + this.enableH264HighProfile = enableH264HighProfile; + } + + @Override + public VideoEncoder createEncoder(VideoCodecInfo input) { + VideoCodecType type = VideoCodecType.valueOf(input.name); + MediaCodecInfo info = findCodecForType(type); + + if (info == null) { + return null; // No support for this type. + } + + String codecName = info.getName(); + String mime = type.mimeType(); + int colorFormat = selectColorFormat(SUPPORTED_COLOR_FORMATS, info.getCapabilitiesForType(mime)); + + return new HardwareVideoEncoder(codecName, type, colorFormat, getKeyFrameIntervalSec(type), + getForcedKeyFrameIntervalMs(type, codecName), createBitrateAdjuster(type, codecName)); + } + + @Override + public VideoCodecInfo[] getSupportedCodecs() { + List supportedCodecInfos = new ArrayList(); + // Generate a list of supported codecs in order of preference: + // 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(); + if (type == VideoCodecType.H264 && isH264HighProfileSupported(codec)) { + supportedCodecInfos.add(new VideoCodecInfo(0, name, getCodecProperties(type, true))); + } + + supportedCodecInfos.add(new VideoCodecInfo(0, name, getCodecProperties(type, false))); + } + } + return supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]); + } + + 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; // No support for this type. + } + + // Returns true if the given MediaCodecInfo indicates a supported encoder for the given type. + private boolean isSupportedCodec(MediaCodecInfo info, VideoCodecType type) { + if (!codecSupportsType(info, type)) { + return false; + } + // Check for a supported color format. + if (selectColorFormat(SUPPORTED_COLOR_FORMATS, info.getCapabilitiesForType(type.mimeType())) + == null) { + return false; + } + return isHardwareSupportedInCurrentSdk(info, type); + } + + private Integer selectColorFormat(int[] supportedColorFormats, CodecCapabilities capabilities) { + for (int supportedColorFormat : supportedColorFormats) { + for (int codecColorFormat : capabilities.colorFormats) { + if (codecColorFormat == supportedColorFormat) { + return codecColorFormat; + } + } + } + return null; + } + + private boolean codecSupportsType(MediaCodecInfo info, VideoCodecType type) { + for (String mimeType : info.getSupportedTypes()) { + if (type.mimeType().equals(mimeType)) { + return true; + } + } + return false; + } + + // Returns true if the given MediaCodecInfo indicates a hardware module that is supported on the + // current 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 isHardwareSupportedInCurrentSdkVp8(MediaCodecInfo info) { + String name = info.getName(); + // QCOM Vp8 encoder is supported in KITKAT or later. + return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) + // Exynos VP8 encoder is supported in M or later. + || (name.startsWith(EXYNOS_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + // Intel Vp8 encoder is supported in LOLLIPOP or later, with the intel encoder enabled. + || (name.startsWith(INTEL_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP + && enableIntelVp8Encoder); + } + + private boolean isHardwareSupportedInCurrentSdkVp9(MediaCodecInfo info) { + String name = info.getName(); + return (name.startsWith(QCOM_PREFIX) || name.startsWith(EXYNOS_PREFIX)) + // Both QCOM and Exynos VP9 encoders are supported in N or later. + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + } + + private boolean isHardwareSupportedInCurrentSdkH264(MediaCodecInfo info) { + // First, H264 hardware might perform poorly on this model. + if (H264_HW_EXCEPTION_MODELS.contains(Build.MODEL)) { + return false; + } + String name = info.getName(); + // QCOM H264 encoder is supported in KITKAT or later. + return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) + // Exynos H264 encoder is supported in LOLLIPOP or later. + || (name.startsWith(EXYNOS_PREFIX) + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); + } + + private int getKeyFrameIntervalSec(VideoCodecType type) { + switch (type) { + case VP8: // Fallthrough intended. + case VP9: + return 100; + case H264: + return 20; + } + throw new IllegalArgumentException("Unsupported VideoCodecType " + type); + } + + private int getForcedKeyFrameIntervalMs(VideoCodecType type, String codecName) { + if (type == VideoCodecType.VP8 && codecName.startsWith(QCOM_PREFIX)) { + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP + || Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1) { + return QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_L_MS; + } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { + return QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_M_MS; + } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + return QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_N_MS; + } + } + // Other codecs don't need key frame forcing. + return 0; + } + + private BitrateAdjuster createBitrateAdjuster(VideoCodecType type, String codecName) { + if (codecName.startsWith(EXYNOS_PREFIX)) { + if (type == VideoCodecType.VP8) { + // Exynos VP8 encoders need dynamic bitrate adjustment. + return new DynamicBitrateAdjuster(); + } else { + // Exynos VP9 and H264 encoders need framerate-based bitrate adjustment. + return new FramerateBitrateAdjuster(); + } + } + // Other codecs don't need bitrate adjustment. + return new BaseBitrateAdjuster(); + } + + private boolean isH264HighProfileSupported(MediaCodecInfo info) { + return enableH264HighProfile && info.getName().startsWith(QCOM_PREFIX); + } + + private Map getCodecProperties(VideoCodecType type, boolean highProfile) { + switch (type) { + case VP8: + case VP9: + return new HashMap(); + case H264: + Map properties = new HashMap<>(); + properties.put(H264_FMTP_LEVEL_ASYMMETRY_ALLOWED, "1"); + properties.put(H264_FMTP_PACKETIZATION_MODE, "1"); + properties.put(H264_FMTP_PROFILE_LEVEL_ID, + highProfile ? H264_CONSTRAINED_HIGH_3_1 : H264_CONSTRAINED_BASELINE_3_1); + return properties; + default: + throw new IllegalArgumentException("Unsupported codec: " + type); + } + } +} diff --git a/webrtc/sdk/android/api/org/webrtc/VideoEncoderFactory.java b/webrtc/sdk/android/api/org/webrtc/VideoEncoderFactory.java new file mode 100644 index 0000000000..e7611ff33f --- /dev/null +++ b/webrtc/sdk/android/api/org/webrtc/VideoEncoderFactory.java @@ -0,0 +1,20 @@ +/* + * Copyright 2017 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; + +/** Factory for creating VideoEncoders. */ +interface VideoEncoderFactory { + /** Creates an encoder for the given video codec. */ + public VideoEncoder createEncoder(VideoCodecInfo info); + + /** Enumerates the list of supported video codecs. */ + public VideoCodecInfo[] getSupportedCodecs(); +} diff --git a/webrtc/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java b/webrtc/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java new file mode 100644 index 0000000000..87fe6ef7bd --- /dev/null +++ b/webrtc/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2017 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.annotation.TargetApi; +import android.graphics.Matrix; +import android.support.test.filters.SmallTest; +import android.util.Log; +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import org.chromium.base.test.BaseJUnit4ClassRunner; +import org.junit.Test; +import org.junit.runner.RunWith; + +@TargetApi(16) +@RunWith(BaseJUnit4ClassRunner.class) +public class HardwareVideoEncoderTest { + final static String TAG = "MediaCodecVideoEncoderTest"; + + private static final boolean ENABLE_INTEL_VP8_ENCODER = true; + private static final boolean ENABLE_H264_HIGH_PROFILE = true; + private static final VideoEncoder.Settings SETTINGS = new VideoEncoder.Settings( + 1 /* core */, 640 /* width */, 480 /* height */, 300 /* kbps */, 30 /* fps */); + + @Test + @SmallTest + public void testInitializeUsingYuvBuffer() { + HardwareVideoEncoderFactory factory = + new HardwareVideoEncoderFactory(ENABLE_INTEL_VP8_ENCODER, ENABLE_H264_HIGH_PROFILE); + VideoCodecInfo[] supportedCodecs = factory.getSupportedCodecs(); + if (supportedCodecs.length == 0) { + Log.w(TAG, "No hardware encoding support, skipping testInitializeUsingYuvBuffer"); + return; + } + VideoEncoder encoder = factory.createEncoder(supportedCodecs[0]); + assertEquals(encoder.initEncode(SETTINGS, null), VideoCodecStatus.OK); + assertEquals(encoder.release(), VideoCodecStatus.OK); + } + + @Test + @SmallTest + public void testEncodeYuvBuffer() throws InterruptedException { + HardwareVideoEncoderFactory factory = + new HardwareVideoEncoderFactory(ENABLE_INTEL_VP8_ENCODER, ENABLE_H264_HIGH_PROFILE); + VideoCodecInfo[] supportedCodecs = factory.getSupportedCodecs(); + if (supportedCodecs.length == 0) { + Log.w(TAG, "No hardware encoding support, skipping testEncodeYuvBuffer"); + return; + } + + VideoEncoder encoder = factory.createEncoder(supportedCodecs[0]); + + final long presentationTimestampUs = 20000; + final CountDownLatch encodeDone = new CountDownLatch(1); + + VideoEncoder.Callback callback = new VideoEncoder.Callback() { + @Override + public void onEncodedFrame(EncodedImage image, VideoEncoder.CodecSpecificInfo info) { + assertTrue(image.buffer.capacity() > 0); + assertEquals(image.encodedWidth, SETTINGS.width); + assertEquals(image.encodedHeight, SETTINGS.height); + assertEquals(image.captureTimeMs, presentationTimestampUs / 1000); + assertEquals(image.frameType, EncodedImage.FrameType.VideoFrameKey); + assertEquals(image.rotation, 0); + assertTrue(image.completeFrame); + + encodeDone.countDown(); + } + }; + + assertEquals(encoder.initEncode(SETTINGS, callback), VideoCodecStatus.OK); + + VideoFrame.I420Buffer buffer = new I420BufferImpl(SETTINGS.width, SETTINGS.height); + VideoFrame frame = + new VideoFrame(buffer, 0 /* rotation */, presentationTimestampUs * 1000, new Matrix()); + VideoEncoder.EncodeInfo info = new VideoEncoder.EncodeInfo( + new EncodedImage.FrameType[] {EncodedImage.FrameType.VideoFrameKey}); + + assertEquals(encoder.encode(frame, info), VideoCodecStatus.OK); + + ThreadUtils.awaitUninterruptibly(encodeDone); + + assertEquals(encoder.release(), VideoCodecStatus.OK); + } +} diff --git a/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java b/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java index d36ef6cf47..105458bd45 100644 --- a/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java +++ b/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java @@ -48,15 +48,8 @@ class HardwareVideoEncoder implements VideoEncoder { private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; private static final int DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US = 100000; - // TODO(mellem): Maybe move mime types to the factory or a common location. - private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; - private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9"; - private static final String H264_MIME_TYPE = "video/avc"; - private static final Set SUPPORTED_MIME_TYPES = - new HashSet<>(Arrays.asList(VP8_MIME_TYPE, VP9_MIME_TYPE, H264_MIME_TYPE)); - private final String codecName; - private final String mimeType; + private final VideoCodecType codecType; private final int colorFormat; private final ColorFormat inputColorFormat; // Base interval for generating key frames. @@ -94,27 +87,23 @@ class HardwareVideoEncoder implements VideoEncoder { private ByteBuffer configBuffer = null; /** - * Creates a new HardwareVideoEncoder with the given codecName, mimeType, colorFormat, key frame + * Creates a new HardwareVideoEncoder with the given codecName, codecType, colorFormat, key frame * intervals, and bitrateAdjuster. * * @param codecName the hardware codec implementation to use - * @param mimeType MIME type of the codec's output; must be one of "video/x-vnd.on2.vp8", - * "video/x-vnd.on2.vp9", or "video/avc" + * @param codecType the type of the given video codec (eg. VP8, VP9, or H264) * @param colorFormat color format used by the input buffer * @param keyFrameIntervalSec interval in seconds between key frames; used to initialize the codec * @param forceKeyFrameIntervalMs interval at which to force a key frame if one is not requested; * used to reduce distortion caused by some codec implementations * @param bitrateAdjuster algorithm used to correct codec implementations that do not produce the * desired bitrates - * @throws IllegalArgumentException if either mimeType or colorFormat is unsupported + * @throws IllegalArgumentException if colorFormat is unsupported */ - public HardwareVideoEncoder(String codecName, String mimeType, int colorFormat, + public HardwareVideoEncoder(String codecName, VideoCodecType codecType, int colorFormat, int keyFrameIntervalSec, int forceKeyFrameIntervalMs, BitrateAdjuster bitrateAdjuster) { - if (!SUPPORTED_MIME_TYPES.contains(mimeType)) { - throw new IllegalArgumentException("Unsupported MIME type: " + mimeType); - } this.codecName = codecName; - this.mimeType = mimeType; + this.codecType = codecType; this.colorFormat = colorFormat; this.inputColorFormat = ColorFormat.valueOf(colorFormat); this.keyFrameIntervalSec = keyFrameIntervalSec; @@ -150,7 +139,7 @@ class HardwareVideoEncoder implements VideoEncoder { return VideoCodecStatus.ERROR; } try { - MediaFormat format = MediaFormat.createVideoFormat(mimeType, width, height); + MediaFormat format = MediaFormat.createVideoFormat(codecType.mimeType(), width, height); format.setInteger(MediaFormat.KEY_BIT_RATE, adjustedBitrate); format.setInteger(KEY_BITRATE_MODE, VIDEO_ControlRateConstant); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); @@ -369,7 +358,7 @@ class HardwareVideoEncoder implements VideoEncoder { ByteBuffer frameBuffer; boolean isKeyFrame = (info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - if (isKeyFrame && mimeType.equals(H264_MIME_TYPE)) { + if (isKeyFrame && codecType == VideoCodecType.H264) { Logging.d(TAG, "Prepending config frame of size " + configBuffer.capacity() + " to output buffer with offset " + info.offset + ", size " + info.size); diff --git a/webrtc/sdk/android/src/java/org/webrtc/I420BufferImpl.java b/webrtc/sdk/android/src/java/org/webrtc/I420BufferImpl.java new file mode 100644 index 0000000000..87fc202ece --- /dev/null +++ b/webrtc/sdk/android/src/java/org/webrtc/I420BufferImpl.java @@ -0,0 +1,85 @@ +/* + * Copyright 2017 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; + +import java.nio.ByteBuffer; +import org.webrtc.VideoFrame.I420Buffer; + +/** Implementation of an I420 VideoFrame buffer. */ +class I420BufferImpl implements VideoFrame.I420Buffer { + private final int width; + private final int height; + private final int strideUV; + private final ByteBuffer y; + private final ByteBuffer u; + private final ByteBuffer v; + + I420BufferImpl(int width, int height) { + this.width = width; + this.height = height; + this.strideUV = (width + 1) / 2; + int halfHeight = (height + 1) / 2; + this.y = ByteBuffer.allocateDirect(width * height); + this.u = ByteBuffer.allocateDirect(strideUV * halfHeight); + this.v = ByteBuffer.allocateDirect(strideUV * halfHeight); + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public ByteBuffer getDataY() { + return y; + } + + @Override + public ByteBuffer getDataU() { + return u; + } + + @Override + public ByteBuffer getDataV() { + return v; + } + + @Override + public int getStrideY() { + return width; + } + + @Override + public int getStrideU() { + return strideUV; + } + + @Override + public int getStrideV() { + return strideUV; + } + + @Override + public I420Buffer toI420() { + return this; + } + + @Override + public void retain() {} + + @Override + public void release() {} +} diff --git a/webrtc/sdk/android/src/java/org/webrtc/VideoCodecType.java b/webrtc/sdk/android/src/java/org/webrtc/VideoCodecType.java new file mode 100644 index 0000000000..2d4ef9ad64 --- /dev/null +++ b/webrtc/sdk/android/src/java/org/webrtc/VideoCodecType.java @@ -0,0 +1,28 @@ +/* + * Copyright 2017 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; + +/** Enumeration of supported video codec types. */ +enum VideoCodecType { + VP8("video/x-vnd.on2.vp8"), + VP9("video/x-vnd.on2.vp9"), + H264("video/avc"); + + private final String mimeType; + + private VideoCodecType(String mimeType) { + this.mimeType = mimeType; + } + + String mimeType() { + return mimeType; + } +}