Index: webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java |
diff --git a/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java b/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java |
index fc868c4b8cbc5473475fb02871ab7334c40a70b0..7bb3857105ecd405c84dae35ea2d62e034fa8fc9 100644 |
--- a/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java |
+++ b/webrtc/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java |
@@ -25,6 +25,7 @@ import java.util.Deque; |
import java.util.HashSet; |
import java.util.Set; |
import java.util.concurrent.LinkedBlockingDeque; |
+import java.util.concurrent.TimeUnit; |
/** Android hardware video encoder. */ |
@TargetApi(19) |
@@ -55,9 +56,9 @@ class HardwareVideoEncoder implements VideoEncoder { |
private final int keyFrameIntervalSec; |
// Interval at which to force a key frame. Used to reduce color distortions caused by some |
// Qualcomm video encoders. |
- private final long forcedKeyFrameMs; |
+ private final long forcedKeyFrameNs; |
// Presentation timestamp of the last requested (or forced) key frame. |
- private long lastKeyFrameMs; |
+ private long lastKeyFrameNs; |
private final BitrateAdjuster bitrateAdjuster; |
private int adjustedBitrate; |
@@ -125,7 +126,7 @@ class HardwareVideoEncoder implements VideoEncoder { |
this.inputColorFormat = null; |
} |
this.keyFrameIntervalSec = keyFrameIntervalSec; |
- this.forcedKeyFrameMs = forceKeyFrameIntervalMs; |
+ this.forcedKeyFrameNs = TimeUnit.MILLISECONDS.toNanos(forceKeyFrameIntervalMs); |
this.bitrateAdjuster = bitrateAdjuster; |
this.outputBuilders = new LinkedBlockingDeque<>(); |
this.textureContext = textureContext; |
@@ -150,7 +151,7 @@ class HardwareVideoEncoder implements VideoEncoder { |
this.callback = callback; |
- lastKeyFrameMs = -1; |
+ lastKeyFrameNs = -1; |
try { |
codec = MediaCodec.createByCodecName(codecName); |
@@ -257,11 +258,8 @@ class HardwareVideoEncoder implements VideoEncoder { |
} |
} |
- // Frame timestamp rounded to the nearest microsecond and millisecond. |
- long presentationTimestampUs = (videoFrame.getTimestampNs() + 500) / 1000; |
- long presentationTimestampMs = (presentationTimestampUs + 500) / 1000; |
- if (requestedKeyFrame || shouldForceKeyFrame(presentationTimestampMs)) { |
- requestKeyFrame(presentationTimestampMs); |
+ if (requestedKeyFrame || shouldForceKeyFrame(videoFrame.getTimestampNs())) { |
+ requestKeyFrame(videoFrame.getTimestampNs()); |
} |
VideoFrame.Buffer videoFrameBuffer = videoFrame.getBuffer(); |
@@ -269,7 +267,7 @@ class HardwareVideoEncoder implements VideoEncoder { |
// subsampled at one byte per four pixels. |
int bufferSize = videoFrameBuffer.getHeight() * videoFrameBuffer.getWidth() * 3 / 2; |
EncodedImage.Builder builder = EncodedImage.builder() |
- .setCaptureTimeMs(presentationTimestampMs) |
+ .setCaptureTimeNs(videoFrame.getTimestampNs()) |
.setCompleteFrame(true) |
.setEncodedWidth(videoFrame.getBuffer().getWidth()) |
.setEncodedHeight(videoFrame.getBuffer().getHeight()) |
@@ -287,7 +285,7 @@ class HardwareVideoEncoder implements VideoEncoder { |
if (videoFrameBuffer instanceof VideoFrame.TextureBuffer) { |
Logging.w(TAG, "Encoding texture buffer in byte mode; this may be inefficient"); |
} |
- return encodeByteBuffer(videoFrame, videoFrameBuffer, bufferSize, presentationTimestampUs); |
+ return encodeByteBuffer(videoFrame, videoFrameBuffer, bufferSize); |
} |
} |
@@ -321,8 +319,11 @@ class HardwareVideoEncoder implements VideoEncoder { |
return VideoCodecStatus.OK; |
} |
- private VideoCodecStatus encodeByteBuffer(VideoFrame videoFrame, |
- VideoFrame.Buffer videoFrameBuffer, int bufferSize, long presentationTimestampUs) { |
+ private VideoCodecStatus encodeByteBuffer( |
+ VideoFrame videoFrame, VideoFrame.Buffer videoFrameBuffer, int bufferSize) { |
+ // Frame timestamp rounded to the nearest microsecond. |
+ long presentationTimestampUs = (videoFrame.getTimestampNs() + 500) / 1000; |
+ |
// No timeout. Don't block for an input buffer, drop frames if the encoder falls behind. |
int index; |
try { |
@@ -397,11 +398,11 @@ class HardwareVideoEncoder implements VideoEncoder { |
return initEncodeInternal(newWidth, newHeight, 0, 0, callback); |
} |
- private boolean shouldForceKeyFrame(long presentationTimestampMs) { |
- return forcedKeyFrameMs > 0 && presentationTimestampMs > lastKeyFrameMs + forcedKeyFrameMs; |
+ private boolean shouldForceKeyFrame(long presentationTimestampNs) { |
+ return forcedKeyFrameNs > 0 && presentationTimestampNs > lastKeyFrameNs + forcedKeyFrameNs; |
} |
- private void requestKeyFrame(long presentationTimestampMs) { |
+ private void requestKeyFrame(long presentationTimestampNs) { |
// 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, |
@@ -414,7 +415,7 @@ class HardwareVideoEncoder implements VideoEncoder { |
Logging.e(TAG, "requestKeyFrame failed", e); |
return; |
} |
- lastKeyFrameMs = presentationTimestampMs; |
+ lastKeyFrameNs = presentationTimestampNs; |
} |
private Thread createOutputThread() { |