commit fa7d0e1257b3fb6b84a02978be0c25664b122766
parent 20ccceccb14fb410de75a67867434695600d314d
Author: Andreas Pehrson <apehrson@mozilla.com>
Date: Fri, 5 Dec 2025 16:34:21 +0000
Bug 1992567 - Enforce a hard limit of 1 frame in flight in WebRTC GMP encoder. r=webrtc-reviewers,bwc
This avoids an ~unbounded memory leak when OpenH264 is not able to keep up with
encoding in real-time.
Also report frame drops from Encode() upwards.
Differential Revision: https://phabricator.services.mozilla.com/D272451
Diffstat:
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/dom/media/webrtc/libwebrtcglue/WebrtcGmpVideoCodec.cpp b/dom/media/webrtc/libwebrtcglue/WebrtcGmpVideoCodec.cpp
@@ -340,6 +340,14 @@ void WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange(uint32_t aWidth,
void WebrtcGmpVideoEncoder::Encode_g(
const webrtc::VideoFrame& aInputImage,
std::vector<webrtc::VideoFrameType> aFrameTypes) {
+ auto reportDroppedOnExit = MakeScopeExit([&] {
+ MutexAutoLock lock(mCallbackMutex);
+ if (mCallback) {
+ mCallback->OnDroppedFrame(
+ webrtc::EncodedImageCallback::DropReason::kDroppedByEncoder);
+ }
+ });
+
if (!mGMP) {
// destroyed via Terminate(), failed to init, or just not initted yet
GMP_LOG_DEBUG("GMP Encode: not initted yet");
@@ -347,6 +355,13 @@ void WebrtcGmpVideoEncoder::Encode_g(
}
MOZ_ASSERT(mHost);
+ if (mInputImageMap.Length() >= kMaxImagesInFlight) {
+ GMP_LOG_WARNING(
+ "GMP Encode: Max number of frames already in flight. Dropping this "
+ "one.");
+ return;
+ }
+
if (static_cast<uint32_t>(aInputImage.width()) != mCodecParams.mWidth ||
static_cast<uint32_t>(aInputImage.height()) != mCodecParams.mHeight) {
GMP_LOG_DEBUG("GMP Encode: resolution change from %ux%u to %dx%d",
@@ -423,18 +438,23 @@ void WebrtcGmpVideoEncoder::Encode_g(
MOZ_RELEASE_ASSERT(mInputImageMap.IsEmpty() ||
mInputImageMap.LastElement().ntp_timestamp_ms <
aInputImage.ntp_time_ms());
- mInputImageMap.AppendElement(
- InputImageData{.gmp_timestamp_us = gmpTimestamp,
- .ntp_timestamp_ms = aInputImage.ntp_time_ms(),
- .timestamp_us = aInputImage.timestamp_us(),
- .rtp_timestamp = aInputImage.rtp_timestamp(),
- .frame_config = frameConfigs[0]});
GMP_LOG_DEBUG("GMP Encode: %" PRIu64, (frame->Timestamp()));
err = mGMP->Encode(std::move(frame), codecSpecificInfo, gmp_frame_types);
if (err != GMPNoErr) {
GMP_LOG_DEBUG("GMP Encode: failed to encode frame");
+ return;
}
+
+ // Once in mInputImageMap, frame drops are reported by GMP callbacks
+ // (Encoded/Dropped).
+ reportDroppedOnExit.release();
+ mInputImageMap.AppendElement(
+ InputImageData{.gmp_timestamp_us = gmpTimestamp,
+ .ntp_timestamp_ms = aInputImage.ntp_time_ms(),
+ .timestamp_us = aInputImage.timestamp_us(),
+ .rtp_timestamp = aInputImage.rtp_timestamp(),
+ .frame_config = frameConfigs[0]});
}
int32_t WebrtcGmpVideoEncoder::RegisterEncodeCompleteCallback(