Chromium Code Reviews| 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 6a218fd56834f649a05e9972f0550fc999ead744..04d94076124dda854e883495c31eaff0c388d5bf 100644 |
| --- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java |
| +++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java |
| @@ -33,8 +33,11 @@ import android.media.MediaCodecInfo.CodecCapabilities; |
| import android.media.MediaCodecInfo; |
| import android.media.MediaCodecList; |
| import android.media.MediaFormat; |
| +import android.opengl.EGLContext; |
| +import android.opengl.GLES20; |
| import android.os.Build; |
| import android.os.Bundle; |
| +import android.view.Surface; |
| import org.webrtc.Logging; |
| @@ -65,6 +68,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 H264_MIME_TYPE = "video/avc"; |
| // List of supported HW VP8 codecs. |
| @@ -117,7 +123,7 @@ public class MediaCodecVideoEncoder { |
| } |
| private static EncoderProperties findHwEncoder( |
| - String mime, String[] supportedHwCodecPrefixes) { |
| + String mime, String[] supportedHwCodecPrefixes, boolean useSurface) { |
| // MediaCodec.setParameters is missing for JB and below, so bitrate |
| // can not be adjusted dynamically. |
| if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { |
| @@ -168,6 +174,18 @@ public class MediaCodecVideoEncoder { |
| Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); |
| } |
| + if (useSurface) { |
| + for (int codecColorFormat : capabilities.colorFormats) { |
| + if (codecColorFormat == CodecCapabilities.COLOR_FormatSurface) { |
| + // Found supported HW encoder. |
| + Logging.d(TAG, "Found target encoder for mime " + mime + " : " + name + |
| + ". Using Surface as input"); |
| + return new EncoderProperties(name, codecColorFormat); |
| + } |
| + } |
| + return null; |
| + } |
| + |
| // Check if codec supports either yuv420 or nv12. |
| for (int supportedColorFormat : supportedColorList) { |
| for (int codecColorFormat : capabilities.colorFormats) { |
| @@ -184,11 +202,19 @@ public class MediaCodecVideoEncoder { |
| } |
| public static boolean isVp8HwSupported() { |
| - return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null; |
| + return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, false) != null; |
| } |
| public static boolean isH264HwSupported() { |
| - return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; |
| + return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, false) != null; |
| + } |
| + |
| + public static boolean isVp8HwSupportedUsingTextures() { |
|
AlexG
2015/10/14 23:48:27
Are these 2 functions called from native code or f
perkj_webrtc
2015/11/16 13:08:51
they are here so that an app can ask if the hw cod
|
| + return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, true) != null; |
| + } |
| + |
| + public static boolean isH264HwSupportedUsingTextures() { |
| + return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, true) != null; |
| } |
| private void checkOnMediaCodecThread() { |
| @@ -209,10 +235,12 @@ 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 ? "True" : "False")); |
| if (mediaCodecThread != null) { |
| throw new RuntimeException("Forgot to release()?"); |
| @@ -222,11 +250,11 @@ 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); |
| 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); |
| keyFrameIntervalSec = 20; |
| } |
| if (properties == null) { |
| @@ -250,6 +278,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(); |
| @@ -291,6 +326,27 @@ 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); |
| + eglBase.swapBuffers(presentationTimestampUs * 1000); |
| + return true; |
| + } |
| + catch (RuntimeException e) { |
| + Logging.e(TAG, "encodeTexture failed", e); |
| + return false; |
| + } |
| + } |
| + |
| void release() { |
| Logging.d(TAG, "Java releaseEncoder"); |
| checkOnMediaCodecThread(); |
| @@ -302,6 +358,15 @@ public class MediaCodecVideoEncoder { |
| } |
| mediaCodec = null; |
| mediaCodecThread = null; |
| + if (drawer != null) { |
| + drawer.release(); |
|
AlexG
2015/10/14 23:48:27
nit: drawer = null and same for 2 checks below?
perkj_webrtc
2015/11/16 13:08:51
Done.
|
| + } |
| + if (eglBase != null) { |
| + eglBase.release(); |
| + } |
| + if (inputSurface != null) { |
| + inputSurface.release(); |
| + } |
| } |
| private boolean setRates(int kbps, int frameRateIgnored) { |