Create VideoDecoderFactory interface and implementation.

The implementation creates an Android hardware video decoder.  It is built
around the same patterns as the HardwareVideoEncoderFactory.

This change pulls some shared code and constants into a common "utils" class.

Finally, adds an instrumentation test for the HardwareVideoDecoder.

BUG=webrtc:7760

Change-Id: Iea6eaae7727925743cb54f7c3153a6c07d62f55d
Reviewed-on: https://chromium-review.googlesource.com/536254
Commit-Queue: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#18686}
This commit is contained in:
Bjorn Mellem
2017-06-20 11:35:04 -07:00
committed by Commit Bot
parent b080b46df4
commit 38145241a2
9 changed files with 354 additions and 87 deletions

View File

@ -341,6 +341,7 @@ android_library("libjingle_peerconnection_java") {
"api/org/webrtc/GlShader.java",
"api/org/webrtc/GlTextureFrameBuffer.java",
"api/org/webrtc/GlUtil.java",
"api/org/webrtc/HardwareVideoDecoderFactory.java",
"api/org/webrtc/HardwareVideoEncoderFactory.java",
"api/org/webrtc/IceCandidate.java",
"api/org/webrtc/MediaCodecVideoDecoder.java",
@ -371,6 +372,7 @@ android_library("libjingle_peerconnection_java") {
"api/org/webrtc/VideoCodecInfo.java",
"api/org/webrtc/VideoCodecStatus.java",
"api/org/webrtc/VideoDecoder.java",
"api/org/webrtc/VideoDecoderFactory.java",
"api/org/webrtc/VideoEncoder.java",
"api/org/webrtc/VideoEncoderFactory.java",
"api/org/webrtc/VideoFileRenderer.java",
@ -393,6 +395,7 @@ android_library("libjingle_peerconnection_java") {
"src/java/org/webrtc/HardwareVideoEncoder.java",
"src/java/org/webrtc/Histogram.java",
"src/java/org/webrtc/I420BufferImpl.java",
"src/java/org/webrtc/MediaCodecUtils.java",
"src/java/org/webrtc/VideoCodecType.java",
"src/java/org/webrtc/WrappedNativeI420Buffer.java",
"src/java/org/webrtc/YuvConverter.java",
@ -426,6 +429,7 @@ if (rtc_include_tests) {
"instrumentationtests/src/org/webrtc/FileVideoCapturerTest.java",
"instrumentationtests/src/org/webrtc/GlRectDrawerTest.java",
"instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java",
"instrumentationtests/src/org/webrtc/HardwareVideoDecoderTest.java",
"instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java",
"instrumentationtests/src/org/webrtc/NetworkMonitorTest.java",
"instrumentationtests/src/org/webrtc/PeerConnectionTest.java",

View File

@ -0,0 +1,100 @@
/*
* 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.webrtc.MediaCodecUtils.EXYNOS_PREFIX;
import static org.webrtc.MediaCodecUtils.INTEL_PREFIX;
import static org.webrtc.MediaCodecUtils.NVIDIA_PREFIX;
import static org.webrtc.MediaCodecUtils.QCOM_PREFIX;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecList;
import android.os.Build;
/** Factory for Android hardware VideoDecoders. */
@SuppressWarnings("deprecation") // API level 16 requires use of deprecated methods.
public class HardwareVideoDecoderFactory implements VideoDecoderFactory {
private static final String TAG = "HardwareVideoDecoderFactory";
@Override
public VideoDecoder createDecoder(String codecType) {
VideoCodecType type = VideoCodecType.valueOf(codecType);
MediaCodecInfo info = findCodecForType(type);
if (info == null) {
return null; // No support for this codec type.
}
CodecCapabilities capabilities = info.getCapabilitiesForType(type.mimeType());
return new HardwareVideoDecoder(info.getName(), type,
MediaCodecUtils.selectColorFormat(MediaCodecUtils.DECODER_COLOR_FORMATS, capabilities));
}
private MediaCodecInfo findCodecForType(VideoCodecType type) {
// HW decoding is not supported on builds before KITKAT.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return null;
}
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 (!MediaCodecUtils.codecSupportsType(info, type)) {
return false;
}
// Check for a supported color format.
if (MediaCodecUtils.selectColorFormat(
MediaCodecUtils.DECODER_COLOR_FORMATS, info.getCapabilitiesForType(type.mimeType()))
== null) {
return false;
}
return isHardwareSupported(info, type);
}
private boolean isHardwareSupported(MediaCodecInfo info, VideoCodecType type) {
String name = info.getName();
switch (type) {
case VP8:
// QCOM, Intel, Exynos, and Nvidia all supported for VP8.
return name.startsWith(QCOM_PREFIX) || name.startsWith(INTEL_PREFIX)
|| name.startsWith(EXYNOS_PREFIX) || name.startsWith(NVIDIA_PREFIX);
case VP9:
// QCOM and Exynos supported for VP9.
return name.startsWith(QCOM_PREFIX) || name.startsWith(EXYNOS_PREFIX);
case H264:
// QCOM, Intel, and Exynos supported for H264.
return name.startsWith(QCOM_PREFIX) || name.startsWith(INTEL_PREFIX)
|| name.startsWith(EXYNOS_PREFIX);
default:
return false;
}
}
}

View File

@ -10,6 +10,10 @@
package org.webrtc;
import static org.webrtc.MediaCodecUtils.EXYNOS_PREFIX;
import static org.webrtc.MediaCodecUtils.INTEL_PREFIX;
import static org.webrtc.MediaCodecUtils.QCOM_PREFIX;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities;
@ -26,11 +30,6 @@ import java.util.Map;
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;
@ -42,17 +41,6 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory {
private static final List<String> 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";
@ -86,7 +74,8 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory {
String codecName = info.getName();
String mime = type.mimeType();
int colorFormat = selectColorFormat(SUPPORTED_COLOR_FORMATS, info.getCapabilitiesForType(mime));
int colorFormat = MediaCodecUtils.selectColorFormat(
MediaCodecUtils.ENCODER_COLOR_FORMATS, info.getCapabilitiesForType(mime));
return new HardwareVideoEncoder(codecName, type, colorFormat, getKeyFrameIntervalSec(type),
getForcedKeyFrameIntervalMs(type, codecName), createBitrateAdjuster(type, codecName));
@ -134,37 +123,18 @@ public class HardwareVideoEncoderFactory implements VideoEncoderFactory {
// 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)) {
if (!MediaCodecUtils.codecSupportsType(info, type)) {
return false;
}
// Check for a supported color format.
if (selectColorFormat(SUPPORTED_COLOR_FORMATS, info.getCapabilitiesForType(type.mimeType()))
if (MediaCodecUtils.selectColorFormat(
MediaCodecUtils.ENCODER_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) {

View File

@ -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 VideoDecoders. */
public interface VideoDecoderFactory {
/**
* Creates a VideoDecoder for the given codec. Supports the same codecs supported by
* VideoEncoderFactory.
*/
public VideoDecoder createDecoder(String codecType);
}

View File

@ -11,7 +11,7 @@
package org.webrtc;
/** Factory for creating VideoEncoders. */
interface VideoEncoderFactory {
public interface VideoEncoderFactory {
/** Creates an encoder for the given video codec. */
public VideoEncoder createEncoder(VideoCodecInfo info);

View File

@ -0,0 +1,125 @@
/*
* 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 android.annotation.TargetApi;
import android.graphics.Matrix;
import android.support.test.filters.MediumTest;
import android.util.Log;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.CountDownLatch;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link HardwareVideoDecoder}. */
@TargetApi(16)
@RunWith(BaseJUnit4ClassRunner.class)
public final class HardwareVideoDecoderTest {
private static final String TAG = "HardwareVideoDecoderTest";
private static final boolean ENABLE_INTEL_VP8_ENCODER = true;
private static final boolean ENABLE_H264_HIGH_PROFILE = true;
private static final VideoDecoder.Settings SETTINGS =
new VideoDecoder.Settings(1 /* core */, 640 /* width */, 480 /* height */);
@Test
@MediumTest
public void testInitialize() {
HardwareVideoEncoderFactory encoderFactory =
new HardwareVideoEncoderFactory(ENABLE_INTEL_VP8_ENCODER, ENABLE_H264_HIGH_PROFILE);
VideoCodecInfo[] supportedCodecs = encoderFactory.getSupportedCodecs();
if (supportedCodecs.length == 0) {
Log.i(TAG, "No hardware encoding support, skipping testInitialize");
return;
}
HardwareVideoDecoderFactory decoderFactory = new HardwareVideoDecoderFactory();
VideoDecoder decoder = decoderFactory.createDecoder(supportedCodecs[0].name);
assertEquals(decoder.initDecode(SETTINGS, null), VideoCodecStatus.OK);
assertEquals(decoder.release(), VideoCodecStatus.OK);
}
@Test
@MediumTest
public void testDecode() throws InterruptedException {
HardwareVideoEncoderFactory encoderFactory =
new HardwareVideoEncoderFactory(ENABLE_INTEL_VP8_ENCODER, ENABLE_H264_HIGH_PROFILE);
VideoCodecInfo[] supportedCodecs = encoderFactory.getSupportedCodecs();
if (supportedCodecs.length == 0) {
Log.i(TAG, "No hardware encoding support, skipping testEncodeYuvBuffer");
return;
}
// Set up the decoder.
HardwareVideoDecoderFactory decoderFactory = new HardwareVideoDecoderFactory();
VideoDecoder decoder = decoderFactory.createDecoder(supportedCodecs[0].name);
final long presentationTimestampUs = 20000;
final CountDownLatch decodeDone = new CountDownLatch(1);
final AtomicReference<VideoFrame> decoded = new AtomicReference<>();
VideoDecoder.Callback decodeCallback = new VideoDecoder.Callback() {
@Override
public void onDecodedFrame(VideoFrame frame, Integer decodeTimeMs, Integer qp) {
decoded.set(frame);
decodeDone.countDown();
}
};
assertEquals(decoder.initDecode(SETTINGS, decodeCallback), VideoCodecStatus.OK);
// Set up an encoder to produce a valid encoded frame.
VideoEncoder encoder = encoderFactory.createEncoder(supportedCodecs[0]);
final CountDownLatch encodeDone = new CountDownLatch(1);
final AtomicReference<EncodedImage> encoded = new AtomicReference<>();
VideoEncoder.Callback encodeCallback = new VideoEncoder.Callback() {
@Override
public void onEncodedFrame(EncodedImage image, VideoEncoder.CodecSpecificInfo info) {
encoded.set(image);
encodeDone.countDown();
}
};
assertEquals(
encoder.initEncode(
new VideoEncoder.Settings(1, SETTINGS.width, SETTINGS.height, 300, 30), encodeCallback),
VideoCodecStatus.OK);
// First, encode a frame.
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);
// Now decode the frame.
assertEquals(
decoder.decode(encoded.get(), new VideoDecoder.DecodeInfo(false, 0)), VideoCodecStatus.OK);
ThreadUtils.awaitUninterruptibly(decodeDone);
frame = decoded.get();
assertEquals(frame.getRotation(), 0);
assertEquals(frame.getTimestampNs(), presentationTimestampUs * 1000);
assertEquals(frame.getTransformMatrix(), new Matrix());
assertEquals(frame.getBuffer().getWidth(), SETTINGS.width);
assertEquals(frame.getBuffer().getHeight(), SETTINGS.height);
assertEquals(decoder.release(), VideoCodecStatus.OK);
assertEquals(encoder.release(), VideoCodecStatus.OK);
}
}

View File

@ -38,13 +38,6 @@ class HardwareVideoDecoder implements VideoDecoder {
private static final String MEDIA_FORMAT_KEY_CROP_TOP = "crop-top";
private static final String MEDIA_FORMAT_KEY_CROP_BOTTOM = "crop-bottom";
// 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_FORMATYVU420PackedSemiPlanar32m4ka = 0x7FA30C01;
private static final int COLOR_QCOM_FORMATYVU420PackedSemiPlanar16m4ka = 0x7FA30C02;
private static final int COLOR_QCOM_FORMATYVU420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03;
private static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
// MediaCodec.release() occasionally hangs. Release stops waiting and reports failure after
// this timeout.
private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000;
@ -132,7 +125,7 @@ class HardwareVideoDecoder implements VideoDecoder {
try {
codec = MediaCodec.createByCodecName(codecName);
} catch (IOException | IllegalArgumentException e) {
Logging.e(TAG, "Cannot create media decoder");
Logging.e(TAG, "Cannot create media decoder " + codecName);
return VideoCodecStatus.ERROR;
}
try {
@ -168,8 +161,8 @@ class HardwareVideoDecoder implements VideoDecoder {
int size = frame.buffer.remaining();
if (size == 0) {
Logging.e(TAG, "decode() - input buffer empty");
return VideoCodecStatus.ERR_PARAMETER;
Logging.e(TAG, "decode() - no input data");
return VideoCodecStatus.ERROR;
}
// Load dimensions from shared memory under the dimension lock.
@ -215,13 +208,13 @@ class HardwareVideoDecoder implements VideoDecoder {
index = codec.dequeueInputBuffer(0 /* timeout */);
} catch (IllegalStateException e) {
Logging.e(TAG, "dequeueInputBuffer failed", e);
return VideoCodecStatus.ERROR;
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
if (index < 0) {
// Decoder is falling behind. No input buffers available.
// The decoder can't simply drop frames; it might lose a key frame.
Logging.e(TAG, "decode() - no HW buffers available; decoder falling behind");
return VideoCodecStatus.ERROR;
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
ByteBuffer buffer;
@ -229,12 +222,12 @@ class HardwareVideoDecoder implements VideoDecoder {
buffer = codec.getInputBuffers()[index];
} catch (IllegalStateException e) {
Logging.e(TAG, "getInputBuffers failed", e);
return VideoCodecStatus.ERROR;
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
if (buffer.capacity() < size) {
Logging.e(TAG, "decode() - HW buffer too small");
return VideoCodecStatus.ERROR;
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
buffer.put(frame.buffer);
@ -245,7 +238,7 @@ class HardwareVideoDecoder implements VideoDecoder {
} catch (IllegalStateException e) {
Logging.e(TAG, "queueInputBuffer failed", e);
decodeStartTimes.pollLast();
return VideoCodecStatus.ERROR;
return VideoCodecStatus.FALLBACK_SOFTWARE;
}
if (keyFrameRequired) {
keyFrameRequired = false;
@ -472,18 +465,12 @@ class HardwareVideoDecoder implements VideoDecoder {
}
private boolean isSupportedColorFormat(int colorFormat) {
switch (colorFormat) {
case CodecCapabilities.COLOR_FormatYUV420Planar:
case CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:
case COLOR_QCOM_FORMATYVU420PackedSemiPlanar32m4ka:
case COLOR_QCOM_FORMATYVU420PackedSemiPlanar16m4ka:
case COLOR_QCOM_FORMATYVU420PackedSemiPlanar64x32Tile2m8ka:
case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
for (int supported : MediaCodecUtils.DECODER_COLOR_FORMATS) {
if (supported == colorFormat) {
return true;
default:
return false;
}
}
return false;
}
private static void copyI420(ByteBuffer src, int offset, VideoFrame.I420Buffer frameBuffer,
@ -505,15 +492,14 @@ class HardwareVideoDecoder implements VideoDecoder {
copyPlane(src, vPos, uvStride, frameBuffer.getDataV(), 0, frameBuffer.getStrideV(), chromaWidth,
chromaHeight);
// If the sliceHeight is odd, duplicate the last rows of chroma. Copy the last row of the U and
// V channels and append them at the end of each channel.
// If the sliceHeight is odd, duplicate the last rows of chroma.
if (sliceHeight % 2 != 0) {
int strideU = frameBuffer.getStrideU();
int endU = chromaHeight * strideU;
copyRow(frameBuffer.getDataU(), endU - strideU, frameBuffer.getDataU(), endU, chromaWidth);
uPos = chromaHeight * strideU;
copyRow(frameBuffer.getDataU(), uPos - strideU, frameBuffer.getDataU(), uPos, chromaWidth);
int strideV = frameBuffer.getStrideV();
int endV = chromaHeight * strideV;
copyRow(frameBuffer.getDataV(), endV - strideV, frameBuffer.getDataV(), endV, chromaWidth);
vPos = chromaHeight * strideV;
copyRow(frameBuffer.getDataV(), vPos - strideV, frameBuffer.getDataV(), vPos, chromaWidth);
}
}

View File

@ -36,10 +36,6 @@ class HardwareVideoEncoder implements VideoEncoder {
// constant until API level 21.
private static final String KEY_BITRATE_MODE = "bitrate-mode";
// 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;
private static final int MAX_VIDEO_FRAMERATE = 30;
// See MAX_ENCODER_Q_SIZE in androidmediaencoder_jni.cc.
@ -133,8 +129,9 @@ class HardwareVideoEncoder implements VideoEncoder {
lastKeyFrameMs = -1;
codec = createCodecByName(codecName);
if (codec == null) {
try {
codec = MediaCodec.createByCodecName(codecName);
} catch (IOException | IllegalArgumentException e) {
Logging.e(TAG, "Cannot create media encoder " + codecName);
return VideoCodecStatus.ERROR;
}
@ -418,15 +415,6 @@ class HardwareVideoEncoder implements VideoEncoder {
}
}
private static MediaCodec createCodecByName(String codecName) {
try {
return MediaCodec.createByCodecName(codecName);
} catch (IOException | IllegalArgumentException e) {
Logging.e(TAG, "createCodecByName failed", e);
return null;
}
}
/**
* Enumeration of supported color formats used for MediaCodec's input.
*/
@ -463,7 +451,7 @@ class HardwareVideoEncoder implements VideoEncoder {
return I420;
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:
case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
case MediaCodecUtils.COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
return NV12;
default:
throw new IllegalArgumentException("Unsupported colorFormat: " + colorFormat);

View File

@ -0,0 +1,74 @@
/*
* 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.MediaCodec;
/** Container class for static constants and helpers used with MediaCodec. */
class MediaCodecUtils {
private static final String TAG = "MediaCodecUtils";
// Prefixes for supported hardware encoder/decoder component names.
static final String EXYNOS_PREFIX = "OMX.Exynos.";
static final String INTEL_PREFIX = "OMX.Intel.";
static final String NVIDIA_PREFIX = "OMX.Nvidia.";
static final String QCOM_PREFIX = "OMX.qcom.";
// NV12 color format supported by QCOM codec, but not declared in MediaCodec -
// see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
static final int COLOR_QCOM_FORMATYVU420PackedSemiPlanar32m4ka = 0x7FA30C01;
static final int COLOR_QCOM_FORMATYVU420PackedSemiPlanar16m4ka = 0x7FA30C02;
static final int COLOR_QCOM_FORMATYVU420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03;
static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
// Color formats supported by hardware decoder - in order of preference.
static final int[] DECODER_COLOR_FORMATS = new int[] {CodecCapabilities.COLOR_FormatYUV420Planar,
CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
MediaCodecUtils.COLOR_QCOM_FORMATYVU420PackedSemiPlanar32m4ka,
MediaCodecUtils.COLOR_QCOM_FORMATYVU420PackedSemiPlanar16m4ka,
MediaCodecUtils.COLOR_QCOM_FORMATYVU420PackedSemiPlanar64x32Tile2m8ka,
MediaCodecUtils.COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m};
// Color formats supported by hardware encoder - in order of preference.
static final int[] ENCODER_COLOR_FORMATS = {
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar,
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
MediaCodecUtils.COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m};
static Integer selectColorFormat(int[] supportedColorFormats, CodecCapabilities capabilities) {
for (int supportedColorFormat : supportedColorFormats) {
for (int codecColorFormat : capabilities.colorFormats) {
if (codecColorFormat == supportedColorFormat) {
return codecColorFormat;
}
}
}
return null;
}
static boolean codecSupportsType(MediaCodecInfo info, VideoCodecType type) {
for (String mimeType : info.getSupportedTypes()) {
if (type.mimeType().equals(mimeType)) {
return true;
}
}
return false;
}
private MediaCodecUtils() {
// This class should not be instantiated.
}
}