| Index: talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| index 8e8b2113ebebac08ca1fe5d5ac6e8476aa477882..47886effd7c36965c31daf7d971a7b3063467f8e 100644
|
| --- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| +++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| @@ -33,8 +33,10 @@ import android.media.MediaCodecInfo.CodecCapabilities;
|
| import android.media.MediaCodecInfo;
|
| import android.media.MediaCodecList;
|
| import android.media.MediaFormat;
|
| +import android.opengl.GLES20;
|
| import android.os.Build;
|
| import android.os.Bundle;
|
| +import android.view.Surface;
|
|
|
| import org.webrtc.Logging;
|
|
|
| @@ -43,6 +45,8 @@ import java.util.Arrays;
|
| import java.util.List;
|
| import java.util.concurrent.CountDownLatch;
|
|
|
| +import javax.microedition.khronos.egl.EGLContext;
|
| +
|
| // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder.
|
| // This class is an implementation detail of the Java PeerConnection API.
|
| @TargetApi(19)
|
| @@ -73,6 +77,9 @@ public class MediaCodecVideoEncoder {
|
| private Thread mediaCodecThread;
|
| private MediaCodec mediaCodec;
|
| private ByteBuffer[] outputBuffers;
|
| + private EglBase eglBase;
|
| + private Surface inputSurface;
|
| + private GlRectDrawer drawer;
|
| 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";
|
| @@ -109,6 +116,9 @@ public class MediaCodecVideoEncoder {
|
| CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
|
| COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
|
| };
|
| + private static final int[] supportedSurfaceColorList = {
|
| + CodecCapabilities.COLOR_FormatSurface
|
| + };
|
| private VideoCodecType type;
|
| private int colorFormat; // Used by native code.
|
|
|
| @@ -138,7 +148,7 @@ public class MediaCodecVideoEncoder {
|
| }
|
|
|
| private static EncoderProperties findHwEncoder(
|
| - String mime, String[] supportedHwCodecPrefixes) {
|
| + String mime, String[] supportedHwCodecPrefixes, int[] colorList) {
|
| // MediaCodec.setParameters is missing for JB and below, so bitrate
|
| // can not be adjusted dynamically.
|
| if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
| @@ -188,8 +198,7 @@ public class MediaCodecVideoEncoder {
|
| Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat));
|
| }
|
|
|
| - // Check if codec supports either yuv420 or nv12.
|
| - for (int supportedColorFormat : supportedColorList) {
|
| + for (int supportedColorFormat : colorList) {
|
| for (int codecColorFormat : capabilities.colorFormats) {
|
| if (codecColorFormat == supportedColorFormat) {
|
| // Found supported HW encoder.
|
| @@ -204,14 +213,30 @@ public class MediaCodecVideoEncoder {
|
| }
|
|
|
| public static boolean isVp8HwSupported() {
|
| - return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null;
|
| + return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, supportedColorList) != null;
|
| }
|
|
|
| public static boolean isVp9HwSupported() {
|
| - return findHwEncoder(VP9_MIME_TYPE, supportedVp9HwCodecPrefixes) != null;
|
| + return findHwEncoder(VP9_MIME_TYPE, supportedVp9HwCodecPrefixes, supportedColorList) != null;
|
| }
|
| +
|
| public static boolean isH264HwSupported() {
|
| - return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null;
|
| + return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, supportedColorList) != null;
|
| + }
|
| +
|
| + public static boolean isVp8HwSupportedUsingTextures() {
|
| + return findHwEncoder(
|
| + VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, supportedSurfaceColorList) != null;
|
| + }
|
| +
|
| + public static boolean isVp9HwSupportedUsingTextures() {
|
| + return findHwEncoder(
|
| + VP9_MIME_TYPE, supportedVp9HwCodecPrefixes, supportedSurfaceColorList) != null;
|
| + }
|
| +
|
| + public static boolean isH264HwSupportedUsingTextures() {
|
| + return findHwEncoder(
|
| + H264_MIME_TYPE, supportedH264HwCodecPrefixes, supportedSurfaceColorList) != null;
|
| }
|
|
|
| private void checkOnMediaCodecThread() {
|
| @@ -244,10 +269,11 @@ public class MediaCodecVideoEncoder {
|
| }
|
| }
|
|
|
| - // Returns false if the hardware encoder currently can't be used.
|
| - boolean initEncode(VideoCodecType type, int width, int height, int kbps, int fps) {
|
| + boolean initEncode(VideoCodecType type, int width, int height, int kbps, int fps,
|
| + EGLContext sharedContext) {
|
| + final boolean useSurface = sharedContext != null;
|
| Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height +
|
| - ". @ " + kbps + " kbps. Fps: " + fps + ".");
|
| + ". @ " + kbps + " kbps. Fps: " + fps + ". Encode from texture : " + useSurface);
|
|
|
| if (mediaCodecThread != null) {
|
| throw new RuntimeException("Forgot to release()?");
|
| @@ -257,15 +283,18 @@ public class MediaCodecVideoEncoder {
|
| int keyFrameIntervalSec = 0;
|
| if (type == VideoCodecType.VIDEO_CODEC_VP8) {
|
| mime = VP8_MIME_TYPE;
|
| - properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes);
|
| + properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes,
|
| + useSurface ? supportedSurfaceColorList : supportedColorList);
|
| keyFrameIntervalSec = 100;
|
| } else if (type == VideoCodecType.VIDEO_CODEC_VP9) {
|
| mime = VP9_MIME_TYPE;
|
| - properties = findHwEncoder(VP9_MIME_TYPE, supportedH264HwCodecPrefixes);
|
| + properties = findHwEncoder(VP9_MIME_TYPE, supportedH264HwCodecPrefixes,
|
| + useSurface ? supportedSurfaceColorList : supportedColorList);
|
| keyFrameIntervalSec = 100;
|
| } else if (type == VideoCodecType.VIDEO_CODEC_H264) {
|
| mime = H264_MIME_TYPE;
|
| - properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes);
|
| + properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes,
|
| + useSurface ? supportedSurfaceColorList : supportedColorList);
|
| keyFrameIntervalSec = 20;
|
| }
|
| if (properties == null) {
|
| @@ -293,6 +322,13 @@ public class MediaCodecVideoEncoder {
|
| mediaCodec.configure(
|
| format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
|
|
| + if (useSurface) {
|
| + eglBase = new EglBase(sharedContext, EglBase.ConfigType.RECORDABLE);
|
| + // Create an input surface and keep a reference since we must release the surface when done.
|
| + inputSurface = mediaCodec.createInputSurface();
|
| + eglBase.createSurface(inputSurface);
|
| + drawer = new GlRectDrawer();
|
| + }
|
| mediaCodec.start();
|
| outputBuffers = mediaCodec.getOutputBuffers();
|
| Logging.d(TAG, "Output buffers: " + outputBuffers.length);
|
| @@ -335,6 +371,29 @@ public class MediaCodecVideoEncoder {
|
| }
|
| }
|
|
|
| + boolean encodeTexture(boolean isKeyframe, int oesTextureId, float[] transformationMatrix,
|
| + long presentationTimestampUs) {
|
| + checkOnMediaCodecThread();
|
| + try {
|
| + if (isKeyframe) {
|
| + Logging.d(TAG, "Sync frame request");
|
| + Bundle b = new Bundle();
|
| + b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
|
| + mediaCodec.setParameters(b);
|
| + }
|
| + eglBase.makeCurrent();
|
| + drawer.drawOes(oesTextureId, transformationMatrix);
|
| + // TODO(perkj): Do we have to call EGLExt.eglPresentationTimeANDROID ?
|
| + // If not, remove |presentationTimestampUs|.
|
| + eglBase.swapBuffers();
|
| + return true;
|
| + }
|
| + catch (RuntimeException e) {
|
| + Logging.e(TAG, "encodeTexture failed", e);
|
| + return false;
|
| + }
|
| + }
|
| +
|
| void release() {
|
| Logging.d(TAG, "Java releaseEncoder");
|
| checkOnMediaCodecThread();
|
| @@ -370,6 +429,18 @@ public class MediaCodecVideoEncoder {
|
|
|
| mediaCodec = null;
|
| mediaCodecThread = null;
|
| + if (drawer != null) {
|
| + drawer.release();
|
| + drawer = null;
|
| + }
|
| + if (eglBase != null) {
|
| + eglBase.release();
|
| + eglBase = null;
|
| + }
|
| + if (inputSurface != null) {
|
| + inputSurface.release();
|
| + inputSurface = null;
|
| + }
|
| runningInstance = null;
|
| Logging.d(TAG, "Java releaseEncoder done");
|
| }
|
|
|