Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(694)

Unified Diff: webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java

Issue 2614823005: Force regular key frame generation when using Qualcomm VP8 HW encoder. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
diff --git a/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java b/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
index 258ef966b1a9cc6167f4eff05e291799126d0f4d..4b9688797e3daa276495d76966cf34437f3f4f58 100644
--- a/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
+++ b/webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
@@ -53,6 +53,9 @@ public class MediaCodecVideoEncoder {
private static final double BITRATE_CORRECTION_MAX_SCALE = 2;
// Amount of correction steps to reach correction maximum scale.
private static final int BITRATE_CORRECTION_STEPS = 10;
+ // Forced key frame interval - used to reduce color distortions on Qualcomm platform.
+ private static final long QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_M_MS = 25000;
+ private static final long QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_N_MS = 15000;
// Active running encoder instance. Set in initEncode() (called from native code)
// and reset to null in release() call.
@@ -160,6 +163,11 @@ public class MediaCodecVideoEncoder {
private int targetBitrateBps;
private int targetFps;
+ // Interval in ms to force key frame generation. Used to reduce the time of color distortions
+ // happened sometime when using Qualcomm video encoder.
+ private long forcedKeyFrameMs;
+ private long lastKeyFrameMs;
+
// SPS and PPS NALs (Config frame) for H.264.
private ByteBuffer configData = null;
@@ -198,6 +206,14 @@ public class MediaCodecVideoEncoder {
&& (findHwEncoder(VP8_MIME_TYPE, vp8HwList, supportedColorList) != null);
}
+ public static EncoderProperties vp8HwEncoderProperties() {
+ if (hwEncoderDisabledTypes.contains(VP8_MIME_TYPE)) {
+ return null;
+ } else {
+ return findHwEncoder(VP8_MIME_TYPE, vp8HwList, supportedColorList);
+ }
+ }
+
public static boolean isVp9HwSupported() {
return !hwEncoderDisabledTypes.contains(VP9_MIME_TYPE)
&& (findHwEncoder(VP9_MIME_TYPE, vp9HwList, supportedColorList) != null);
@@ -224,7 +240,7 @@ public class MediaCodecVideoEncoder {
}
// Helper struct for findHwEncoder() below.
- private static class EncoderProperties {
+ public static class EncoderProperties {
public EncoderProperties(
String codecName, int colorFormat, BitrateAdjustmentType bitrateAdjustmentType) {
this.codecName = codecName;
@@ -395,8 +411,19 @@ public class MediaCodecVideoEncoder {
} else {
fps = Math.min(fps, MAXIMUM_INITIAL_FPS);
}
+
+ forcedKeyFrameMs = 0;
+ lastKeyFrameMs = -1;
+ if (properties.codecName.startsWith(qcomVp8HwProperties.codecPrefix)) {
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
+ forcedKeyFrameMs = QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_M_MS;
+ } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
+ forcedKeyFrameMs = QCOM_VP8_KEY_FRAME_INTERVAL_ANDROID_N_MS;
+ }
+ }
+
Logging.d(TAG, "Color format: " + colorFormat + ". Bitrate adjustment: " + bitrateAdjustmentType
- + ". Initial fps: " + fps);
+ + ". Key frame interval: " + forcedKeyFrameMs + " . Initial fps: " + fps);
targetBitrateBps = 1000 * kbps;
targetFps = fps;
bitrateAccumulatorMax = targetBitrateBps / 8.0;
@@ -445,20 +472,38 @@ public class MediaCodecVideoEncoder {
return inputBuffers;
}
+ void checkKeyFrameRequired(boolean requestedKeyFrame, long presentationTimestampUs) {
+ long presentationTimestampMs = (presentationTimestampUs + 500) / 1000;
+ if (lastKeyFrameMs < 0) {
+ lastKeyFrameMs = presentationTimestampMs;
+ }
+ boolean forcedKeyFrame = false;
+ if (!requestedKeyFrame && forcedKeyFrameMs > 0
+ && presentationTimestampMs > lastKeyFrameMs + forcedKeyFrameMs) {
+ forcedKeyFrame = true;
+ }
+ if (requestedKeyFrame || forcedKeyFrame) {
+ // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could
+ // indicate this in queueInputBuffer() below and guarantee _this_ frame
+ // be encoded as a key frame, but sadly that flag is ignored. Instead,
+ // we request a key frame "soon".
+ if (requestedKeyFrame) {
+ Logging.d(TAG, "Sync frame request");
+ } else {
+ Logging.d(TAG, "Sync frame forced");
+ }
+ Bundle b = new Bundle();
+ b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
+ mediaCodec.setParameters(b);
+ lastKeyFrameMs = presentationTimestampMs;
+ }
+ }
+
boolean encodeBuffer(
boolean isKeyframe, int inputBuffer, int size, long presentationTimestampUs) {
checkOnMediaCodecThread();
try {
- if (isKeyframe) {
- // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could
- // indicate this in queueInputBuffer() below and guarantee _this_ frame
- // be encoded as a key frame, but sadly that flag is ignored. Instead,
- // we request a key frame "soon".
- Logging.d(TAG, "Sync frame request");
- Bundle b = new Bundle();
- b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
- mediaCodec.setParameters(b);
- }
+ checkKeyFrameRequired(isKeyframe, presentationTimestampUs);
mediaCodec.queueInputBuffer(inputBuffer, 0, size, presentationTimestampUs, 0);
return true;
} catch (IllegalStateException e) {
@@ -471,12 +516,7 @@ public class MediaCodecVideoEncoder {
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);
- }
+ checkKeyFrameRequired(isKeyframe, presentationTimestampUs);
eglBase.makeCurrent();
// TODO(perkj): glClear() shouldn't be necessary since every pixel is covered anyway,
// but it's a workaround for bug webrtc:5147.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698