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}
This commit is contained in:
Philipp Hancke 2022-11-04 14:45:23 +01:00 committed by WebRTC LUCI CQ
parent 140eb82acd
commit a1b4eb2196
19 changed files with 83 additions and 35 deletions

View File

@ -105,7 +105,9 @@ class RTC_EXPORT RtpSenderInterface : public rtc::RefCountInterface {
encoder_selector) = 0; encoder_selector) = 0;
// TODO(crbug.com/1354101): make pure virtual again after Chrome roll. // 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: protected:
~RtpSenderInterface() override = default; ~RtpSenderInterface() override = default;

View File

@ -253,7 +253,7 @@ class VideoSendStream {
virtual Stats GetStats() = 0; virtual Stats GetStats() = 0;
virtual void GenerateKeyFrame() = 0; virtual void GenerateKeyFrame(const std::vector<std::string>& rids) = 0;
protected: protected:
virtual ~VideoSendStream() {} virtual ~VideoSendStream() {}

View File

@ -428,7 +428,9 @@ void FakeVideoMediaChannel::ClearRecordableEncodedFrameCallback(uint32_t ssrc) {
} }
void FakeVideoMediaChannel::RequestRecvKeyFrame(uint32_t ssrc) {} 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) { FakeVoiceEngine::FakeVoiceEngine() : fail_create_channel_(false) {
// Add a fake audio codec. Note that the name must not be "" as there are // Add a fake audio codec. Note that the name must not be "" as there are

View File

@ -463,7 +463,8 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
override; override;
void ClearRecordableEncodedFrameCallback(uint32_t ssrc) override; void ClearRecordableEncodedFrameCallback(uint32_t ssrc) override;
void RequestRecvKeyFrame(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: private:
bool SetRecvCodecs(const std::vector<VideoCodec>& codecs); bool SetRecvCodecs(const std::vector<VideoCodec>& codecs);

View File

@ -926,7 +926,8 @@ class VideoMediaChannel : public MediaChannel, public Delayable {
// RTCP feedback. // RTCP feedback.
virtual void RequestRecvKeyFrame(uint32_t ssrc) = 0; virtual void RequestRecvKeyFrame(uint32_t ssrc) = 0;
// Cause generation of a keyframe for `ssrc` on a sending channel. // 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; virtual std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const = 0;
}; };

View File

@ -194,7 +194,7 @@ class FakeVideoSendStream final
rtc::VideoSourceInterface<webrtc::VideoFrame>* source() const { rtc::VideoSourceInterface<webrtc::VideoFrame>* source() const {
return source_; return source_;
} }
void GenerateKeyFrame() override {} void GenerateKeyFrame(const std::vector<std::string>& rids) override {}
private: private:
// rtc::VideoSinkInterface<VideoFrame> implementation. // rtc::VideoSinkInterface<VideoFrame> implementation.

View File

@ -2828,10 +2828,11 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::RecreateWebRtcStream() {
} }
} }
void WebRtcVideoChannel::WebRtcVideoSendStream::GenerateKeyFrame() { void WebRtcVideoChannel::WebRtcVideoSendStream::GenerateKeyFrame(
const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(&thread_checker_); RTC_DCHECK_RUN_ON(&thread_checker_);
if (stream_ != NULL) { if (stream_ != NULL) {
stream_->GenerateKeyFrame(); stream_->GenerateKeyFrame(rids);
} else { } else {
RTC_LOG(LS_WARNING) RTC_LOG(LS_WARNING)
<< "Absent send stream; ignoring request to generate keyframe."; << "Absent send stream; ignoring request to generate keyframe.";
@ -3572,11 +3573,13 @@ void WebRtcVideoChannel::RequestRecvKeyFrame(uint32_t ssrc) {
} }
} }
void WebRtcVideoChannel::GenerateSendKeyFrame(uint32_t ssrc) { void WebRtcVideoChannel::GenerateSendKeyFrame(
uint32_t ssrc,
const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(&thread_checker_); RTC_DCHECK_RUN_ON(&thread_checker_);
auto it = send_streams_.find(ssrc); auto it = send_streams_.find(ssrc);
if (it != send_streams_.end()) { if (it != send_streams_.end()) {
it->second->GenerateKeyFrame(); it->second->GenerateKeyFrame(rids);
} else { } else {
RTC_LOG(LS_ERROR) RTC_LOG(LS_ERROR)
<< "Absent send stream; ignoring key frame generation for ssrc " << "Absent send stream; ignoring key frame generation for ssrc "

View File

@ -249,7 +249,8 @@ class WebRtcVideoChannel : public VideoMediaChannel,
override; override;
void ClearRecordableEncodedFrameCallback(uint32_t ssrc) override; void ClearRecordableEncodedFrameCallback(uint32_t ssrc) override;
void RequestRecvKeyFrame(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( void SetEncoderToPacketizerFrameTransformer(
uint32_t ssrc, uint32_t ssrc,
@ -391,7 +392,7 @@ class WebRtcVideoChannel : public VideoMediaChannel,
void SetEncoderToPacketizerFrameTransformer( void SetEncoderToPacketizerFrameTransformer(
rtc::scoped_refptr<webrtc::FrameTransformerInterface> rtc::scoped_refptr<webrtc::FrameTransformerInterface>
frame_transformer); frame_transformer);
void GenerateKeyFrame(); void GenerateKeyFrame(const std::vector<std::string>& rids);
private: private:
// Parameters needed to reconstruct the underlying stream. // Parameters needed to reconstruct the underlying stream.

View File

@ -596,7 +596,8 @@ rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
return dtmf_sender_proxy_; return dtmf_sender_proxy_;
} }
RTCError AudioRtpSender::GenerateKeyFrame() { RTCError AudioRtpSender::GenerateKeyFrame(
const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(signaling_thread_); RTC_DCHECK_RUN_ON(signaling_thread_);
RTC_DLOG(LS_ERROR) << "Tried to get generate a key frame for audio."; RTC_DLOG(LS_ERROR) << "Tried to get generate a key frame for audio.";
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
@ -693,11 +694,15 @@ rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
return nullptr; return nullptr;
} }
RTCError VideoRtpSender::GenerateKeyFrame() { RTCError VideoRtpSender::GenerateKeyFrame(
const std::vector<std::string>& rids) {
RTC_DCHECK_RUN_ON(signaling_thread_); 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_) { if (video_media_channel() && ssrc_ && !stopped_) {
worker_thread_->PostTask( worker_thread_->PostTask([&, rids] {
[&] { video_media_channel()->GenerateSendKeyFrame(ssrc_); }); video_media_channel()->GenerateSendKeyFrame(ssrc_, rids);
});
} else { } else {
RTC_LOG(LS_WARNING) << "Tried to generate key frame for sender that is " RTC_LOG(LS_WARNING) << "Tried to generate key frame for sender that is "
"stopped or has no media channel."; "stopped or has no media channel.";

View File

@ -351,7 +351,7 @@ class AudioRtpSender : public DtmfProviderInterface, public RtpSenderBase {
} }
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override; rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
RTCError GenerateKeyFrame() override; RTCError GenerateKeyFrame(const std::vector<std::string>& rids) override;
protected: protected:
AudioRtpSender(rtc::Thread* worker_thread, AudioRtpSender(rtc::Thread* worker_thread,
@ -411,7 +411,7 @@ class VideoRtpSender : public RtpSenderBase {
} }
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override; 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; RTCError CheckSVCParameters(const RtpParameters& parameters) override;

View File

@ -48,7 +48,7 @@ PROXY_METHOD1(void,
PROXY_METHOD1(void, PROXY_METHOD1(void,
SetEncoderSelector, SetEncoderSelector,
std::unique_ptr<VideoEncoderFactory::EncoderSelectorInterface>) std::unique_ptr<VideoEncoderFactory::EncoderSelectorInterface>)
PROXY_METHOD0(RTCError, GenerateKeyFrame) PROXY_METHOD1(RTCError, GenerateKeyFrame, const std::vector<std::string>&)
END_PROXY_MAP(RtpSender) END_PROXY_MAP(RtpSender)
} // namespace webrtc } // namespace webrtc

View File

@ -50,7 +50,10 @@ class VideoRtpReceiverTest : public testing::Test {
(uint32_t), (uint32_t),
(override)); (override));
MOCK_METHOD(void, RequestRecvKeyFrame, (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> { class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {

View File

@ -16,6 +16,8 @@
#include "test/gtest.h" #include "test/gtest.h"
#include "video/test/mock_video_stream_encoder.h" #include "video/test/mock_video_stream_encoder.h"
using ::testing::_;
namespace webrtc { namespace webrtc {
class VieKeyRequestTest : public ::testing::Test { class VieKeyRequestTest : public ::testing::Test {
@ -38,18 +40,18 @@ class VieKeyRequestTest : public ::testing::Test {
}; };
TEST_F(VieKeyRequestTest, CreateAndTriggerRequests) { TEST_F(VieKeyRequestTest, CreateAndTriggerRequests) {
EXPECT_CALL(encoder_, SendKeyFrame()).Times(1); EXPECT_CALL(encoder_, SendKeyFrame(_)).Times(1);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc); encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
} }
TEST_F(VieKeyRequestTest, TooManyOnReceivedIntraFrameRequest) { 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);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc); encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
simulated_clock_.AdvanceTimeMilliseconds(10); simulated_clock_.AdvanceTimeMilliseconds(10);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc); encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
EXPECT_CALL(encoder_, SendKeyFrame()).Times(1); EXPECT_CALL(encoder_, SendKeyFrame(_)).Times(1);
simulated_clock_.AdvanceTimeMilliseconds(300); simulated_clock_.AdvanceTimeMilliseconds(300);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc); encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);
encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc); encoder_rtcp_feedback_.OnReceivedIntraFrameRequest(kSsrc);

View File

@ -34,7 +34,10 @@ class MockVideoStreamEncoder : public VideoStreamEncoderInterface {
(override)); (override));
MOCK_METHOD(void, SetSink, (EncoderSink*, bool), (override)); MOCK_METHOD(void, SetSink, (EncoderSink*, bool), (override));
MOCK_METHOD(void, SetStartBitrate, (int), (override)); MOCK_METHOD(void, SetStartBitrate, (int), (override));
MOCK_METHOD(void, SendKeyFrame, (), (override)); MOCK_METHOD(void,
SendKeyFrame,
(const std::vector<VideoFrameType>&),
(override));
MOCK_METHOD(void, MOCK_METHOD(void,
OnLossNotification, OnLossNotification,
(const VideoEncoder::LossNotification&), (const VideoEncoder::LossNotification&),

View File

@ -343,9 +343,24 @@ void VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
send_stream_.DeliverRtcp(packet, length); 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_) { if (video_stream_encoder_) {
video_stream_encoder_->SendKeyFrame(); video_stream_encoder_->SendKeyFrame(next_frames);
} }
} }

View File

@ -13,6 +13,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#include "api/fec_controller.h" #include "api/fec_controller.h"
@ -93,7 +94,7 @@ class VideoSendStream : public webrtc::VideoSendStream {
void StopPermanentlyAndGetRtpStates(RtpStateMap* rtp_state_map, void StopPermanentlyAndGetRtpStates(RtpStateMap* rtp_state_map,
RtpPayloadStateMap* payload_state_map); RtpPayloadStateMap* payload_state_map);
void GenerateKeyFrame() override; void GenerateKeyFrame(const std::vector<std::string>& rids) override;
private: private:
friend class test::VideoSendStreamPeer; friend class test::VideoSendStreamPeer;

View File

@ -1981,9 +1981,10 @@ void VideoStreamEncoder::RequestRefreshFrame() {
})); }));
} }
void VideoStreamEncoder::SendKeyFrame() { void VideoStreamEncoder::SendKeyFrame(
const std::vector<VideoFrameType>& layers) {
if (!encoder_queue_.IsCurrent()) { if (!encoder_queue_.IsCurrent()) {
encoder_queue_.PostTask([this] { SendKeyFrame(); }); encoder_queue_.PostTask([this, layers] { SendKeyFrame(layers); });
return; return;
} }
RTC_DCHECK_RUN_ON(&encoder_queue_); RTC_DCHECK_RUN_ON(&encoder_queue_);
@ -1998,10 +1999,16 @@ void VideoStreamEncoder::SendKeyFrame() {
return; // Shutting down, or not configured yet. return; // Shutting down, or not configured yet.
} }
// TODO(webrtc:10615): Map keyframe request to spatial layer. 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(), std::fill(next_frame_types_.begin(), next_frame_types_.end(),
VideoFrameType::kVideoFrameKey); VideoFrameType::kVideoFrameKey);
} }
}
void VideoStreamEncoder::OnLossNotification( void VideoStreamEncoder::OnLossNotification(
const VideoEncoder::LossNotification& loss_notification) { const VideoEncoder::LossNotification& loss_notification) {

View File

@ -111,7 +111,7 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
// guaranteed that no encoded frames will be delivered to the sink. // guaranteed that no encoded frames will be delivered to the sink.
void Stop() override; void Stop() override;
void SendKeyFrame() override; void SendKeyFrame(const std::vector<VideoFrameType>& layers = {}) override;
void OnLossNotification( void OnLossNotification(
const VideoEncoder::LossNotification& loss_notification) override; const VideoEncoder::LossNotification& loss_notification) override;

View File

@ -97,8 +97,10 @@ class VideoStreamEncoderInterface {
// resolution. Should be replaced by a construction time setting. // resolution. Should be replaced by a construction time setting.
virtual void SetStartBitrate(int start_bitrate_bps) = 0; virtual void SetStartBitrate(int start_bitrate_bps) = 0;
// Request a key frame. Used for signalling from the remote receiver. // Request a key frame. Used for signalling from the remote receiver with
virtual void SendKeyFrame() = 0; // 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. // Inform the encoder that a loss has occurred.
virtual void OnLossNotification( virtual void OnLossNotification(