generateKeyFrame: add rids argument
and do the resolution of rids to layers. This has no effect yet
since the simulcast encoder adapter (SimulcastEncoderAdapter::Encode), the VP8 encoder (LibvpxVp8Encoder::Encode) and the OpenH264 encoder (H264EncoderImpl::Encode) all generate a key frame for all layers whenever a key frame is requested on one layer.
BUG=chromium:1354101
Change-Id: I13f5f1bf136839a68942b0f6bf4f2d5890415250
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280945
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38565}
diff --git a/api/rtp_sender_interface.h b/api/rtp_sender_interface.h
index 6fc658f..7e84cd4 100644
--- a/api/rtp_sender_interface.h
+++ b/api/rtp_sender_interface.h
@@ -105,7 +105,9 @@
encoder_selector) = 0;
// TODO(crbug.com/1354101): make pure virtual again after Chrome roll.
- virtual RTCError GenerateKeyFrame() { return RTCError::OK(); }
+ virtual RTCError GenerateKeyFrame(const std::vector<std::string>& rids) {
+ return RTCError::OK();
+ }
protected:
~RtpSenderInterface() override = default;
diff --git a/call/video_send_stream.h b/call/video_send_stream.h
index 4946253..5fd0beb 100644
--- a/call/video_send_stream.h
+++ b/call/video_send_stream.h
@@ -253,7 +253,7 @@
virtual Stats GetStats() = 0;
- virtual void GenerateKeyFrame() = 0;
+ virtual void GenerateKeyFrame(const std::vector<std::string>& rids) = 0;
protected:
virtual ~VideoSendStream() {}
diff --git a/media/base/fake_media_engine.cc b/media/base/fake_media_engine.cc
index 60f158e..383939a 100644
--- a/media/base/fake_media_engine.cc
+++ b/media/base/fake_media_engine.cc
@@ -428,7 +428,9 @@
}
void FakeVideoMediaChannel::RequestRecvKeyFrame(uint32_t ssrc) {}
-void FakeVideoMediaChannel::GenerateSendKeyFrame(uint32_t ssrc) {}
+void FakeVideoMediaChannel::GenerateSendKeyFrame(
+ uint32_t ssrc,
+ const std::vector<std::string>& rids) {}
FakeVoiceEngine::FakeVoiceEngine() : fail_create_channel_(false) {
// Add a fake audio codec. Note that the name must not be "" as there are
diff --git a/media/base/fake_media_engine.h b/media/base/fake_media_engine.h
index b98a2da..ece77e5 100644
--- a/media/base/fake_media_engine.h
+++ b/media/base/fake_media_engine.h
@@ -463,7 +463,8 @@
override;
void ClearRecordableEncodedFrameCallback(uint32_t ssrc) override;
void RequestRecvKeyFrame(uint32_t ssrc) override;
- void GenerateSendKeyFrame(uint32_t ssrc) override;
+ void GenerateSendKeyFrame(uint32_t ssrc,
+ const std::vector<std::string>& rids) override;
private:
bool SetRecvCodecs(const std::vector<VideoCodec>& codecs);
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index 721bbd3..5f1d545 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -926,7 +926,8 @@
// RTCP feedback.
virtual void RequestRecvKeyFrame(uint32_t ssrc) = 0;
// Cause generation of a keyframe for `ssrc` on a sending channel.
- virtual void GenerateSendKeyFrame(uint32_t ssrc) = 0;
+ virtual void GenerateSendKeyFrame(uint32_t ssrc,
+ const std::vector<std::string>& rids) = 0;
virtual std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const = 0;
};
diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h
index 65ee0d5..1e0568e 100644
--- a/media/engine/fake_webrtc_call.h
+++ b/media/engine/fake_webrtc_call.h
@@ -194,7 +194,7 @@
rtc::VideoSourceInterface<webrtc::VideoFrame>* source() const {
return source_;
}
- void GenerateKeyFrame() override {}
+ void GenerateKeyFrame(const std::vector<std::string>& rids) override {}
private:
// rtc::VideoSinkInterface<VideoFrame> implementation.
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 419cf95..5ab7a01 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -2828,10 +2828,11 @@
}
}
-void WebRtcVideoChannel::WebRtcVideoSendStream::GenerateKeyFrame() {
+void WebRtcVideoChannel::WebRtcVideoSendStream::GenerateKeyFrame(
+ const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(&thread_checker_);
if (stream_ != NULL) {
- stream_->GenerateKeyFrame();
+ stream_->GenerateKeyFrame(rids);
} else {
RTC_LOG(LS_WARNING)
<< "Absent send stream; ignoring request to generate keyframe.";
@@ -3572,11 +3573,13 @@
}
}
-void WebRtcVideoChannel::GenerateSendKeyFrame(uint32_t ssrc) {
+void WebRtcVideoChannel::GenerateSendKeyFrame(
+ uint32_t ssrc,
+ const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(&thread_checker_);
auto it = send_streams_.find(ssrc);
if (it != send_streams_.end()) {
- it->second->GenerateKeyFrame();
+ it->second->GenerateKeyFrame(rids);
} else {
RTC_LOG(LS_ERROR)
<< "Absent send stream; ignoring key frame generation for ssrc "
diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h
index a0150a8..ee5b8c3 100644
--- a/media/engine/webrtc_video_engine.h
+++ b/media/engine/webrtc_video_engine.h
@@ -249,7 +249,8 @@
override;
void ClearRecordableEncodedFrameCallback(uint32_t ssrc) override;
void RequestRecvKeyFrame(uint32_t ssrc) override;
- void GenerateSendKeyFrame(uint32_t ssrc) override;
+ void GenerateSendKeyFrame(uint32_t ssrc,
+ const std::vector<std::string>& rids) override;
void SetEncoderToPacketizerFrameTransformer(
uint32_t ssrc,
@@ -391,7 +392,7 @@
void SetEncoderToPacketizerFrameTransformer(
rtc::scoped_refptr<webrtc::FrameTransformerInterface>
frame_transformer);
- void GenerateKeyFrame();
+ void GenerateKeyFrame(const std::vector<std::string>& rids);
private:
// Parameters needed to reconstruct the underlying stream.
diff --git a/pc/rtp_sender.cc b/pc/rtp_sender.cc
index 98e86b3..43744ab 100644
--- a/pc/rtp_sender.cc
+++ b/pc/rtp_sender.cc
@@ -596,7 +596,8 @@
return dtmf_sender_proxy_;
}
-RTCError AudioRtpSender::GenerateKeyFrame() {
+RTCError AudioRtpSender::GenerateKeyFrame(
+ const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(signaling_thread_);
RTC_DLOG(LS_ERROR) << "Tried to get generate a key frame for audio.";
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
@@ -693,11 +694,15 @@
return nullptr;
}
-RTCError VideoRtpSender::GenerateKeyFrame() {
+RTCError VideoRtpSender::GenerateKeyFrame(
+ const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(signaling_thread_);
+ // TODO(crbug.com/1354101): check that rids are a subset of this senders rids
+ // (or empty).
if (video_media_channel() && ssrc_ && !stopped_) {
- worker_thread_->PostTask(
- [&] { video_media_channel()->GenerateSendKeyFrame(ssrc_); });
+ worker_thread_->PostTask([&, rids] {
+ video_media_channel()->GenerateSendKeyFrame(ssrc_, rids);
+ });
} else {
RTC_LOG(LS_WARNING) << "Tried to generate key frame for sender that is "
"stopped or has no media channel.";
diff --git a/pc/rtp_sender.h b/pc/rtp_sender.h
index 2cfa08d..70a9c94 100644
--- a/pc/rtp_sender.h
+++ b/pc/rtp_sender.h
@@ -351,7 +351,7 @@
}
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
- RTCError GenerateKeyFrame() override;
+ RTCError GenerateKeyFrame(const std::vector<std::string>& rids) override;
protected:
AudioRtpSender(rtc::Thread* worker_thread,
@@ -411,7 +411,7 @@
}
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
- RTCError GenerateKeyFrame() override;
+ RTCError GenerateKeyFrame(const std::vector<std::string>& rids) override;
RTCError CheckSVCParameters(const RtpParameters& parameters) override;
diff --git a/pc/rtp_sender_proxy.h b/pc/rtp_sender_proxy.h
index 376fd29..a38c8af 100644
--- a/pc/rtp_sender_proxy.h
+++ b/pc/rtp_sender_proxy.h
@@ -48,7 +48,7 @@
PROXY_METHOD1(void,
SetEncoderSelector,
std::unique_ptr<VideoEncoderFactory::EncoderSelectorInterface>)
-PROXY_METHOD0(RTCError, GenerateKeyFrame)
+PROXY_METHOD1(RTCError, GenerateKeyFrame, const std::vector<std::string>&)
END_PROXY_MAP(RtpSender)
} // namespace webrtc
diff --git a/pc/video_rtp_receiver_unittest.cc b/pc/video_rtp_receiver_unittest.cc
index c266459..3ec9a28 100644
--- a/pc/video_rtp_receiver_unittest.cc
+++ b/pc/video_rtp_receiver_unittest.cc
@@ -50,7 +50,10 @@
(uint32_t),
(override));
MOCK_METHOD(void, RequestRecvKeyFrame, (uint32_t), (override));
- MOCK_METHOD(void, GenerateSendKeyFrame, (uint32_t), (override));
+ MOCK_METHOD(void,
+ GenerateSendKeyFrame,
+ (uint32_t, const std::vector<std::string>&),
+ (override));
};
class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
diff --git a/video/encoder_rtcp_feedback_unittest.cc b/video/encoder_rtcp_feedback_unittest.cc
index 4cbb747..f1ac65d 100644
--- a/video/encoder_rtcp_feedback_unittest.cc
+++ b/video/encoder_rtcp_feedback_unittest.cc
@@ -16,6 +16,8 @@
#include "test/gtest.h"
#include "video/test/mock_video_stream_encoder.h"
+using ::testing::_;
+
namespace webrtc {
class VieKeyRequestTest : public ::testing::Test {
@@ -38,18 +40,18 @@
};
TEST_F(VieKeyRequestTest, CreateAndTriggerRequests) {
- EXPECT_CALL(encoder_, SendKeyFrame()).Times(1);
+ EXPECT_CALL(encoder_, SendKeyFrame(_)).Times(1);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
}
TEST_F(VieKeyRequestTest, TooManyOnReceivedIntraFrameRequest) {
- EXPECT_CALL(encoder_, SendKeyFrame()).Times(1);
+ EXPECT_CALL(encoder_, SendKeyFrame(_)).Times(1);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
simulated_clock_.AdvanceTimeMilliseconds(10);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
- EXPECT_CALL(encoder_, SendKeyFrame()).Times(1);
+ EXPECT_CALL(encoder_, SendKeyFrame(_)).Times(1);
simulated_clock_.AdvanceTimeMilliseconds(300);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
diff --git a/video/test/mock_video_stream_encoder.h b/video/test/mock_video_stream_encoder.h
index ff246df..2f98215 100644
--- a/video/test/mock_video_stream_encoder.h
+++ b/video/test/mock_video_stream_encoder.h
@@ -34,7 +34,10 @@
(override));
MOCK_METHOD(void, SetSink, (EncoderSink*, bool), (override));
MOCK_METHOD(void, SetStartBitrate, (int), (override));
- MOCK_METHOD(void, SendKeyFrame, (), (override));
+ MOCK_METHOD(void,
+ SendKeyFrame,
+ (const std::vector<VideoFrameType>&),
+ (override));
MOCK_METHOD(void,
OnLossNotification,
(const VideoEncoder::LossNotification&),
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index f245332..bf5f99a 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -343,9 +343,24 @@
send_stream_.DeliverRtcp(packet, length);
}
-void VideoSendStream::GenerateKeyFrame() {
+void VideoSendStream::GenerateKeyFrame(const std::vector<std::string>& rids) {
+ // Map rids to layers. If rids is empty, generate a keyframe for all layers.
+ std::vector<VideoFrameType> next_frames(config_.rtp.ssrcs.size(),
+ VideoFrameType::kVideoFrameKey);
+ if (!config_.rtp.rids.empty() && !rids.empty()) {
+ std::fill(next_frames.begin(), next_frames.end(),
+ VideoFrameType::kVideoFrameDelta);
+ for (const auto& rid : rids) {
+ for (size_t i = 0; i < config_.rtp.rids.size(); i++) {
+ if (config_.rtp.rids[i] == rid) {
+ next_frames[i] = VideoFrameType::kVideoFrameKey;
+ break;
+ }
+ }
+ }
+ }
if (video_stream_encoder_) {
- video_stream_encoder_->SendKeyFrame();
+ video_stream_encoder_->SendKeyFrame(next_frames);
}
}
diff --git a/video/video_send_stream.h b/video/video_send_stream.h
index a776373..4174d2e 100644
--- a/video/video_send_stream.h
+++ b/video/video_send_stream.h
@@ -13,6 +13,7 @@
#include <map>
#include <memory>
+#include <string>
#include <vector>
#include "api/fec_controller.h"
@@ -93,7 +94,7 @@
void StopPermanentlyAndGetRtpStates(RtpStateMap* rtp_state_map,
RtpPayloadStateMap* payload_state_map);
- void GenerateKeyFrame() override;
+ void GenerateKeyFrame(const std::vector<std::string>& rids) override;
private:
friend class test::VideoSendStreamPeer;
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index 746ee79..de40ccf 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -1981,9 +1981,10 @@
}));
}
-void VideoStreamEncoder::SendKeyFrame() {
+void VideoStreamEncoder::SendKeyFrame(
+ const std::vector<VideoFrameType>& layers) {
if (!encoder_queue_.IsCurrent()) {
- encoder_queue_.PostTask([this] { SendKeyFrame(); });
+ encoder_queue_.PostTask([this, layers] { SendKeyFrame(layers); });
return;
}
RTC_DCHECK_RUN_ON(&encoder_queue_);
@@ -1998,9 +1999,15 @@
return; // Shutting down, or not configured yet.
}
- // TODO(webrtc:10615): Map keyframe request to spatial layer.
- std::fill(next_frame_types_.begin(), next_frame_types_.end(),
- VideoFrameType::kVideoFrameKey);
+ if (!layers.empty()) {
+ RTC_DCHECK_EQ(layers.size(), next_frame_types_.size());
+ for (size_t i = 0; i < layers.size() && i < next_frame_types_.size(); i++) {
+ next_frame_types_[i] = layers[i];
+ }
+ } else {
+ std::fill(next_frame_types_.begin(), next_frame_types_.end(),
+ VideoFrameType::kVideoFrameKey);
+ }
}
void VideoStreamEncoder::OnLossNotification(
diff --git a/video/video_stream_encoder.h b/video/video_stream_encoder.h
index 9af2e0b..e94c369 100644
--- a/video/video_stream_encoder.h
+++ b/video/video_stream_encoder.h
@@ -111,7 +111,7 @@
// guaranteed that no encoded frames will be delivered to the sink.
void Stop() override;
- void SendKeyFrame() override;
+ void SendKeyFrame(const std::vector<VideoFrameType>& layers = {}) override;
void OnLossNotification(
const VideoEncoder::LossNotification& loss_notification) override;
diff --git a/video/video_stream_encoder_interface.h b/video/video_stream_encoder_interface.h
index 38f180d..e716572 100644
--- a/video/video_stream_encoder_interface.h
+++ b/video/video_stream_encoder_interface.h
@@ -97,8 +97,10 @@
// resolution. Should be replaced by a construction time setting.
virtual void SetStartBitrate(int start_bitrate_bps) = 0;
- // Request a key frame. Used for signalling from the remote receiver.
- virtual void SendKeyFrame() = 0;
+ // Request a key frame. Used for signalling from the remote receiver with
+ // no arguments and for RTCRtpSender.generateKeyFrame with a list of
+ // rids/layers.
+ virtual void SendKeyFrame(const std::vector<VideoFrameType>& layers = {}) = 0;
// Inform the encoder that a loss has occurred.
virtual void OnLossNotification(