OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 package org.webrtc; | 11 package org.webrtc; |
12 | 12 |
13 import android.annotation.TargetApi; | 13 import android.annotation.TargetApi; |
14 import android.graphics.Matrix; | 14 import android.graphics.Matrix; |
15 import android.media.MediaCodec; | 15 import android.media.MediaCodec; |
16 import android.media.MediaCodecInfo; | 16 import android.media.MediaCodecInfo; |
17 import android.media.MediaFormat; | 17 import android.media.MediaFormat; |
18 import android.opengl.GLES20; | 18 import android.opengl.GLES20; |
19 import android.os.Bundle; | 19 import android.os.Bundle; |
20 import android.view.Surface; | 20 import android.view.Surface; |
21 import java.io.IOException; | 21 import java.io.IOException; |
22 import java.nio.ByteBuffer; | 22 import java.nio.ByteBuffer; |
23 import java.util.Arrays; | |
24 import java.util.Deque; | 23 import java.util.Deque; |
25 import java.util.HashSet; | 24 import java.util.Map; |
26 import java.util.Set; | |
27 import java.util.concurrent.LinkedBlockingDeque; | 25 import java.util.concurrent.LinkedBlockingDeque; |
28 import java.util.concurrent.TimeUnit; | 26 import java.util.concurrent.TimeUnit; |
29 | 27 |
30 /** Android hardware video encoder. */ | 28 /** Android hardware video encoder. */ |
31 @TargetApi(19) | 29 @TargetApi(19) |
32 @SuppressWarnings("deprecation") // Cannot support API level 19 without using de
precated methods. | 30 @SuppressWarnings("deprecation") // Cannot support API level 19 without using de
precated methods. |
33 class HardwareVideoEncoder implements VideoEncoder { | 31 class HardwareVideoEncoder implements VideoEncoder { |
34 private static final String TAG = "HardwareVideoEncoder"; | 32 private static final String TAG = "HardwareVideoEncoder"; |
35 | 33 |
36 // Bitrate modes - should be in sync with OMX_VIDEO_CONTROLRATETYPE defined | 34 // Bitrate modes - should be in sync with OMX_VIDEO_CONTROLRATETYPE defined |
37 // in OMX_Video.h | 35 // in OMX_Video.h |
38 private static final int VIDEO_ControlRateConstant = 2; | 36 private static final int VIDEO_ControlRateConstant = 2; |
39 // Key associated with the bitrate control mode value (above). Not present as
a MediaFormat | 37 // Key associated with the bitrate control mode value (above). Not present as
a MediaFormat |
40 // constant until API level 21. | 38 // constant until API level 21. |
41 private static final String KEY_BITRATE_MODE = "bitrate-mode"; | 39 private static final String KEY_BITRATE_MODE = "bitrate-mode"; |
42 | 40 |
| 41 private static final int VIDEO_AVC_PROFILE_HIGH = 8; |
| 42 private static final int VIDEO_AVC_LEVEL_3 = 0x100; |
| 43 |
43 private static final int MAX_VIDEO_FRAMERATE = 30; | 44 private static final int MAX_VIDEO_FRAMERATE = 30; |
44 | 45 |
45 // See MAX_ENCODER_Q_SIZE in androidmediaencoder_jni.cc. | 46 // See MAX_ENCODER_Q_SIZE in androidmediaencoder_jni.cc. |
46 private static final int MAX_ENCODER_Q_SIZE = 2; | 47 private static final int MAX_ENCODER_Q_SIZE = 2; |
47 | 48 |
48 private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; | 49 private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; |
49 private static final int DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US = 100000; | 50 private static final int DEQUEUE_OUTPUT_BUFFER_TIMEOUT_US = 100000; |
50 | 51 |
51 private final String codecName; | 52 private final String codecName; |
52 private final VideoCodecType codecType; | 53 private final VideoCodecType codecType; |
53 private final int colorFormat; | 54 private final int colorFormat; |
| 55 private final Map<String, String> params; |
54 private final ColorFormat inputColorFormat; | 56 private final ColorFormat inputColorFormat; |
55 // Base interval for generating key frames. | 57 // Base interval for generating key frames. |
56 private final int keyFrameIntervalSec; | 58 private final int keyFrameIntervalSec; |
57 // Interval at which to force a key frame. Used to reduce color distortions ca
used by some | 59 // Interval at which to force a key frame. Used to reduce color distortions ca
used by some |
58 // Qualcomm video encoders. | 60 // Qualcomm video encoders. |
59 private final long forcedKeyFrameNs; | 61 private final long forcedKeyFrameNs; |
60 // Presentation timestamp of the last requested (or forced) key frame. | 62 // Presentation timestamp of the last requested (or forced) key frame. |
61 private long lastKeyFrameNs; | 63 private long lastKeyFrameNs; |
62 | 64 |
63 private final BitrateAdjuster bitrateAdjuster; | 65 private final BitrateAdjuster bitrateAdjuster; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 * @param codecType the type of the given video codec (eg. VP8, VP9, or H264) | 110 * @param codecType the type of the given video codec (eg. VP8, VP9, or H264) |
109 * @param colorFormat color format used by the input buffer | 111 * @param colorFormat color format used by the input buffer |
110 * @param keyFrameIntervalSec interval in seconds between key frames; used to
initialize the codec | 112 * @param keyFrameIntervalSec interval in seconds between key frames; used to
initialize the codec |
111 * @param forceKeyFrameIntervalMs interval at which to force a key frame if on
e is not requested; | 113 * @param forceKeyFrameIntervalMs interval at which to force a key frame if on
e is not requested; |
112 * used to reduce distortion caused by some codec implementations | 114 * used to reduce distortion caused by some codec implementations |
113 * @param bitrateAdjuster algorithm used to correct codec implementations that
do not produce the | 115 * @param bitrateAdjuster algorithm used to correct codec implementations that
do not produce the |
114 * desired bitrates | 116 * desired bitrates |
115 * @throws IllegalArgumentException if colorFormat is unsupported | 117 * @throws IllegalArgumentException if colorFormat is unsupported |
116 */ | 118 */ |
117 public HardwareVideoEncoder(String codecName, VideoCodecType codecType, int co
lorFormat, | 119 public HardwareVideoEncoder(String codecName, VideoCodecType codecType, int co
lorFormat, |
118 int keyFrameIntervalSec, int forceKeyFrameIntervalMs, BitrateAdjuster bitr
ateAdjuster, | 120 Map<String, String> params, int keyFrameIntervalSec, int forceKeyFrameInte
rvalMs, |
119 EglBase14.Context textureContext) { | 121 BitrateAdjuster bitrateAdjuster, EglBase14.Context textureContext) { |
120 this.codecName = codecName; | 122 this.codecName = codecName; |
121 this.codecType = codecType; | 123 this.codecType = codecType; |
122 this.colorFormat = colorFormat; | 124 this.colorFormat = colorFormat; |
| 125 this.params = params; |
123 if (textureContext == null) { | 126 if (textureContext == null) { |
124 this.inputColorFormat = ColorFormat.valueOf(colorFormat); | 127 this.inputColorFormat = ColorFormat.valueOf(colorFormat); |
125 } else { | 128 } else { |
126 // ColorFormat copies bytes between buffers. It is not used in texture mo
de. | 129 // ColorFormat copies bytes between buffers. It is not used in texture mo
de. |
127 this.inputColorFormat = null; | 130 this.inputColorFormat = null; |
128 } | 131 } |
129 this.keyFrameIntervalSec = keyFrameIntervalSec; | 132 this.keyFrameIntervalSec = keyFrameIntervalSec; |
130 this.forcedKeyFrameNs = TimeUnit.MILLISECONDS.toNanos(forceKeyFrameIntervalM
s); | 133 this.forcedKeyFrameNs = TimeUnit.MILLISECONDS.toNanos(forceKeyFrameIntervalM
s); |
131 this.bitrateAdjuster = bitrateAdjuster; | 134 this.bitrateAdjuster = bitrateAdjuster; |
132 this.outputBuilders = new LinkedBlockingDeque<>(); | 135 this.outputBuilders = new LinkedBlockingDeque<>(); |
(...skipping 29 matching lines...) Expand all Loading... |
162 Logging.e(TAG, "Cannot create media encoder " + codecName); | 165 Logging.e(TAG, "Cannot create media encoder " + codecName); |
163 return VideoCodecStatus.ERROR; | 166 return VideoCodecStatus.ERROR; |
164 } | 167 } |
165 try { | 168 try { |
166 MediaFormat format = MediaFormat.createVideoFormat(codecType.mimeType(), w
idth, height); | 169 MediaFormat format = MediaFormat.createVideoFormat(codecType.mimeType(), w
idth, height); |
167 format.setInteger(MediaFormat.KEY_BIT_RATE, adjustedBitrate); | 170 format.setInteger(MediaFormat.KEY_BIT_RATE, adjustedBitrate); |
168 format.setInteger(KEY_BITRATE_MODE, VIDEO_ControlRateConstant); | 171 format.setInteger(KEY_BITRATE_MODE, VIDEO_ControlRateConstant); |
169 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); | 172 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); |
170 format.setInteger(MediaFormat.KEY_FRAME_RATE, bitrateAdjuster.getAdjustedF
ramerate()); | 173 format.setInteger(MediaFormat.KEY_FRAME_RATE, bitrateAdjuster.getAdjustedF
ramerate()); |
171 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); | 174 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); |
| 175 if (codecType == VideoCodecType.H264) { |
| 176 String profileLevelId = params.get(VideoCodecInfo.H264_FMTP_PROFILE_LEVE
L_ID); |
| 177 if (profileLevelId == null) { |
| 178 profileLevelId = VideoCodecInfo.H264_CONSTRAINED_BASELINE_3_1; |
| 179 } |
| 180 switch (profileLevelId) { |
| 181 case VideoCodecInfo.H264_CONSTRAINED_HIGH_3_1: |
| 182 format.setInteger("profile", VIDEO_AVC_PROFILE_HIGH); |
| 183 format.setInteger("level", VIDEO_AVC_LEVEL_3); |
| 184 break; |
| 185 case VideoCodecInfo.H264_CONSTRAINED_BASELINE_3_1: |
| 186 break; |
| 187 default: |
| 188 Logging.w(TAG, "Unknown profile level id: " + profileLevelId); |
| 189 } |
| 190 } |
172 Logging.d(TAG, "Format: " + format); | 191 Logging.d(TAG, "Format: " + format); |
173 codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); | 192 codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); |
174 | 193 |
175 if (textureContext != null) { | 194 if (textureContext != null) { |
176 // Texture mode. | 195 // Texture mode. |
177 textureEglBase = new EglBase14(textureContext, EglBase.CONFIG_RECORDABLE
); | 196 textureEglBase = new EglBase14(textureContext, EglBase.CONFIG_RECORDABLE
); |
178 textureInputSurface = codec.createInputSurface(); | 197 textureInputSurface = codec.createInputSurface(); |
179 textureEglBase.createSurface(textureInputSurface); | 198 textureEglBase.createSurface(textureInputSurface); |
180 textureDrawer = new GlRectDrawer(); | 199 textureDrawer = new GlRectDrawer(); |
181 } | 200 } |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar: | 572 case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar: |
554 case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar: | 573 case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar: |
555 case MediaCodecUtils.COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: | 574 case MediaCodecUtils.COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: |
556 return NV12; | 575 return NV12; |
557 default: | 576 default: |
558 throw new IllegalArgumentException("Unsupported colorFormat: " + color
Format); | 577 throw new IllegalArgumentException("Unsupported colorFormat: " + color
Format); |
559 } | 578 } |
560 } | 579 } |
561 } | 580 } |
562 } | 581 } |
OLD | NEW |