Remove WebRtcVideoSendStream2::VideoSink inheritance. Remove sending black frame on source removal.
BUG=webrtc:6371,webrtc:6983 Review-Url: https://codereview.webrtc.org/2469993003 Cr-Commit-Position: refs/heads/master@{#16048}
This commit is contained in:
parent
c5da08fc12
commit
d533aec3b8
@ -830,14 +830,12 @@ class VideoMediaChannelTest : public testing::Test,
|
||||
rtc::Thread::Current()->ProcessMessages(30);
|
||||
// Remove the capturer.
|
||||
EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, nullptr));
|
||||
// Wait for one black frame for removing the capturer.
|
||||
EXPECT_FRAME_WAIT(2, kVideoWidth, kVideoHeight, kTimeout);
|
||||
|
||||
// No capturer was added, so this SetVideoSend shouldn't do anything.
|
||||
EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, nullptr));
|
||||
rtc::Thread::Current()->ProcessMessages(300);
|
||||
// Verify no more frames were sent.
|
||||
EXPECT_EQ(2, renderer_.num_rendered_frames());
|
||||
EXPECT_EQ(1, renderer_.num_rendered_frames());
|
||||
}
|
||||
|
||||
// Tests that we can add and remove capturer as unique sources.
|
||||
|
||||
@ -1553,8 +1553,7 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
|
||||
parameters_(std::move(config), options, max_bitrate_bps, codec_settings),
|
||||
rtp_parameters_(CreateRtpParametersWithOneEncoding()),
|
||||
allocated_encoder_(nullptr, cricket::VideoCodec(), false),
|
||||
sending_(false),
|
||||
last_frame_timestamp_us_(0) {
|
||||
sending_(false) {
|
||||
parameters_.config.rtp.max_packet_size = kVideoMtu;
|
||||
parameters_.conference_mode = send_params.conference_mode;
|
||||
|
||||
@ -1612,43 +1611,6 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::~WebRtcVideoSendStream() {
|
||||
DestroyVideoEncoder(&allocated_encoder_);
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame(
|
||||
const webrtc::VideoFrame& frame) {
|
||||
TRACE_EVENT0("webrtc", "WebRtcVideoSendStream::OnFrame");
|
||||
webrtc::VideoFrame video_frame(frame.video_frame_buffer(),
|
||||
frame.rotation(),
|
||||
frame.timestamp_us());
|
||||
|
||||
rtc::CritScope cs(&lock_);
|
||||
|
||||
if (video_frame.width() != last_frame_info_.width ||
|
||||
video_frame.height() != last_frame_info_.height ||
|
||||
video_frame.rotation() != last_frame_info_.rotation ||
|
||||
video_frame.is_texture() != last_frame_info_.is_texture) {
|
||||
last_frame_info_.width = video_frame.width();
|
||||
last_frame_info_.height = video_frame.height();
|
||||
last_frame_info_.rotation = video_frame.rotation();
|
||||
last_frame_info_.is_texture = video_frame.is_texture();
|
||||
|
||||
LOG(LS_INFO) << "Video frame parameters changed: dimensions="
|
||||
<< last_frame_info_.width << "x" << last_frame_info_.height
|
||||
<< ", rotation=" << last_frame_info_.rotation
|
||||
<< ", texture=" << last_frame_info_.is_texture;
|
||||
}
|
||||
|
||||
if (encoder_sink_ == NULL) {
|
||||
// Frame input before send codecs are configured, dropping frame.
|
||||
return;
|
||||
}
|
||||
|
||||
last_frame_timestamp_us_ = video_frame.timestamp_us();
|
||||
|
||||
// Forward frame to the encoder regardless if we are sending or not. This is
|
||||
// to ensure that the encoder can be reconfigured with the correct frame size
|
||||
// as quickly as possible.
|
||||
encoder_sink_->OnFrame(video_frame);
|
||||
}
|
||||
|
||||
bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoSend(
|
||||
bool enable,
|
||||
const VideoOptions* options,
|
||||
@ -1658,7 +1620,6 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoSend(
|
||||
|
||||
// Ignore |options| pointer if |enable| is false.
|
||||
bool options_present = enable && options;
|
||||
bool source_changing = source_ != source;
|
||||
|
||||
if (options_present) {
|
||||
VideoOptions old_options = parameters_.options;
|
||||
@ -1668,29 +1629,6 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoSend(
|
||||
}
|
||||
}
|
||||
|
||||
if (source_changing) {
|
||||
rtc::CritScope cs(&lock_);
|
||||
if (source == nullptr && last_frame_info_.width > 0 && encoder_sink_) {
|
||||
LOG(LS_VERBOSE) << "Disabling capturer, sending black frame.";
|
||||
// Force this black frame not to be dropped due to timestamp order
|
||||
// check. As IncomingCapturedFrame will drop the frame if this frame's
|
||||
// timestamp is less than or equal to last frame's timestamp, it is
|
||||
// necessary to give this black frame a larger timestamp than the
|
||||
// previous one.
|
||||
last_frame_timestamp_us_ += rtc::kNumMicrosecsPerMillisec;
|
||||
rtc::scoped_refptr<webrtc::I420Buffer> black_buffer(
|
||||
webrtc::I420Buffer::Create(last_frame_info_.width,
|
||||
last_frame_info_.height));
|
||||
webrtc::I420Buffer::SetBlack(black_buffer);
|
||||
|
||||
encoder_sink_->OnFrame(webrtc::VideoFrame(
|
||||
black_buffer, last_frame_info_.rotation, last_frame_timestamp_us_));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(perkj, nisse): Remove |source_| and directly call
|
||||
// |stream_|->SetSource(source) once the video frame types have been
|
||||
// merged.
|
||||
if (source_ && stream_) {
|
||||
stream_->SetSource(
|
||||
nullptr, webrtc::VideoSendStream::DegradationPreference::kBalanced);
|
||||
@ -1700,6 +1638,8 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoSend(
|
||||
if (source && stream_) {
|
||||
// Do not adapt resolution for screen content as this will likely
|
||||
// result in blurry and unreadable text.
|
||||
// |this| acts like a VideoSource to make sure SinkWants are handled on the
|
||||
// correct thread.
|
||||
stream_->SetSource(
|
||||
this, enable_cpu_overuse_detection_ &&
|
||||
!parameters_.options.is_screencast.value_or(false)
|
||||
@ -1973,45 +1913,35 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSend(bool send) {
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel2::WebRtcVideoSendStream::RemoveSink(
|
||||
VideoSinkInterface<webrtc::VideoFrame>* sink) {
|
||||
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
{
|
||||
rtc::CritScope cs(&lock_);
|
||||
RTC_DCHECK(encoder_sink_ == sink);
|
||||
encoder_sink_ = nullptr;
|
||||
}
|
||||
source_->RemoveSink(this);
|
||||
RTC_DCHECK(encoder_sink_ == sink);
|
||||
encoder_sink_ = nullptr;
|
||||
source_->RemoveSink(sink);
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel2::WebRtcVideoSendStream::AddOrUpdateSink(
|
||||
VideoSinkInterface<webrtc::VideoFrame>* sink,
|
||||
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
|
||||
const rtc::VideoSinkWants& wants) {
|
||||
if (worker_thread_ == rtc::Thread::Current()) {
|
||||
// AddOrUpdateSink is called on |worker_thread_| if this is the first
|
||||
// registration of |sink|.
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
{
|
||||
rtc::CritScope cs(&lock_);
|
||||
encoder_sink_ = sink;
|
||||
}
|
||||
source_->AddOrUpdateSink(this, wants);
|
||||
encoder_sink_ = sink;
|
||||
source_->AddOrUpdateSink(encoder_sink_, wants);
|
||||
} else {
|
||||
// Subsequent calls to AddOrUpdateSink will happen on the encoder task
|
||||
// queue.
|
||||
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, [this, wants] {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
bool encoder_sink_valid = true;
|
||||
{
|
||||
rtc::CritScope cs(&lock_);
|
||||
encoder_sink_valid = encoder_sink_ != nullptr;
|
||||
}
|
||||
// Since |source_| is still valid after a call to RemoveSink, check if
|
||||
// |encoder_sink_| is still valid to check if this call should be
|
||||
// cancelled.
|
||||
if (source_ && encoder_sink_valid) {
|
||||
source_->AddOrUpdateSink(this, wants);
|
||||
}
|
||||
});
|
||||
invoker_.AsyncInvoke<void>(
|
||||
RTC_FROM_HERE, worker_thread_, [this, sink, wants] {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
// |sink| may be invalidated after this task was posted since
|
||||
// RemoveSink is called on the worker thread.
|
||||
bool encoder_sink_valid = (sink == encoder_sink_);
|
||||
if (source_ && encoder_sink_valid) {
|
||||
source_->AddOrUpdateSink(encoder_sink_, wants);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2135,12 +2065,10 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
|
||||
parameters_.encoder_config.encoder_specific_settings = NULL;
|
||||
|
||||
if (source_) {
|
||||
// TODO(perkj, nisse): Remove |source_| and directly call
|
||||
// |stream_|->SetSource(source) once the video frame types have been
|
||||
// merged and |stream_| internally reconfigure the encoder on frame
|
||||
// resolution change.
|
||||
// Do not adapt resolution for screen content as this will likely result in
|
||||
// blurry and unreadable text.
|
||||
// |this| acts like a VideoSource to make sure SinkWants are handled on the
|
||||
// correct thread.
|
||||
stream_->SetSource(
|
||||
this, enable_cpu_overuse_detection_ &&
|
||||
!parameters_.options.is_screencast.value_or(false)
|
||||
|
||||
@ -231,11 +231,9 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
|
||||
static std::string CodecSettingsVectorToString(
|
||||
const std::vector<VideoCodecSettings>& codecs);
|
||||
|
||||
// Wrapper for the sender part, this is where the source is connected and
|
||||
// frames are then converted from cricket frames to webrtc frames.
|
||||
// Wrapper for the sender part.
|
||||
class WebRtcVideoSendStream
|
||||
: public rtc::VideoSinkInterface<webrtc::VideoFrame>,
|
||||
public rtc::VideoSourceInterface<webrtc::VideoFrame> {
|
||||
: public rtc::VideoSourceInterface<webrtc::VideoFrame> {
|
||||
public:
|
||||
WebRtcVideoSendStream(
|
||||
webrtc::Call* call,
|
||||
@ -256,14 +254,12 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
|
||||
|
||||
// Implements rtc::VideoSourceInterface<webrtc::VideoFrame>.
|
||||
// WebRtcVideoSendStream acts as a source to the webrtc::VideoSendStream
|
||||
// in |stream_|.
|
||||
// TODO(perkj, nisse): Refactor WebRtcVideoSendStream to directly connect
|
||||
// the camera input |source_|
|
||||
void AddOrUpdateSink(VideoSinkInterface<webrtc::VideoFrame>* sink,
|
||||
// in |stream_|. This is done to proxy VideoSinkWants from the encoder to
|
||||
// the worker thread.
|
||||
void AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
|
||||
const rtc::VideoSinkWants& wants) override;
|
||||
void RemoveSink(VideoSinkInterface<webrtc::VideoFrame>* sink) override;
|
||||
void RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) override;
|
||||
|
||||
void OnFrame(const webrtc::VideoFrame& frame) override;
|
||||
bool SetVideoSend(bool mute,
|
||||
const VideoOptions* options,
|
||||
rtc::VideoSourceInterface<webrtc::VideoFrame>* source);
|
||||
@ -306,21 +302,6 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
|
||||
bool external;
|
||||
};
|
||||
|
||||
// TODO(perkj): VideoFrameInfo is currently used for sending a black frame
|
||||
// when the video source is removed. Consider moving that logic to
|
||||
// VieEncoder or remove it.
|
||||
struct VideoFrameInfo {
|
||||
VideoFrameInfo()
|
||||
: width(0),
|
||||
height(0),
|
||||
rotation(webrtc::kVideoRotation_0),
|
||||
is_texture(false) {}
|
||||
int width;
|
||||
int height;
|
||||
webrtc::VideoRotation rotation;
|
||||
bool is_texture;
|
||||
};
|
||||
|
||||
rtc::scoped_refptr<webrtc::VideoEncoderConfig::EncoderSpecificSettings>
|
||||
ConfigureVideoEncoderSettings(const VideoCodec& codec);
|
||||
AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec);
|
||||
@ -348,10 +329,9 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
|
||||
WebRtcVideoEncoderFactory* const external_encoder_factory_
|
||||
ACCESS_ON(&thread_checker_);
|
||||
|
||||
rtc::CriticalSection lock_;
|
||||
webrtc::VideoSendStream* stream_ ACCESS_ON(&thread_checker_);
|
||||
rtc::VideoSinkInterface<webrtc::VideoFrame>* encoder_sink_
|
||||
GUARDED_BY(lock_);
|
||||
ACCESS_ON(&thread_checker_);
|
||||
// Contains settings that are the same for all streams in the MediaChannel,
|
||||
// such as codecs, header extensions, and the global bitrate limit for the
|
||||
// entire channel.
|
||||
@ -363,13 +343,8 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport {
|
||||
// one stream per MediaChannel.
|
||||
webrtc::RtpParameters rtp_parameters_ ACCESS_ON(&thread_checker_);
|
||||
AllocatedEncoder allocated_encoder_ ACCESS_ON(&thread_checker_);
|
||||
VideoFrameInfo last_frame_info_ GUARDED_BY(lock_);
|
||||
|
||||
bool sending_ ACCESS_ON(&thread_checker_);
|
||||
|
||||
// The timestamp of the last frame received
|
||||
// Used to generate timestamp for the black frame when source is removed
|
||||
int64_t last_frame_timestamp_us_ GUARDED_BY(lock_);
|
||||
};
|
||||
|
||||
// Wrapper for the receiver part, contains configs etc. that are needed to
|
||||
|
||||
@ -1654,8 +1654,7 @@ TEST_F(WebRtcVideoChannel2Test, UsesCorrectSettingsForScreencast) {
|
||||
<< "Non-screenshare shouldn't use min-transmit bitrate.";
|
||||
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, true, nullptr, nullptr));
|
||||
// Removing a capturer triggers a black frame to be sent.
|
||||
EXPECT_EQ(2, send_stream->GetNumberOfSwappedFrames());
|
||||
EXPECT_EQ(1, send_stream->GetNumberOfSwappedFrames());
|
||||
VideoOptions screencast_options;
|
||||
screencast_options.is_screencast = rtc::Optional<bool>(true);
|
||||
EXPECT_TRUE(
|
||||
@ -1663,7 +1662,7 @@ TEST_F(WebRtcVideoChannel2Test, UsesCorrectSettingsForScreencast) {
|
||||
EXPECT_TRUE(capturer.CaptureFrame());
|
||||
// Send stream not recreated after option change.
|
||||
ASSERT_EQ(send_stream, fake_call_->GetVideoSendStreams().front());
|
||||
EXPECT_EQ(3, send_stream->GetNumberOfSwappedFrames());
|
||||
EXPECT_EQ(2, send_stream->GetNumberOfSwappedFrames());
|
||||
|
||||
// Verify screencast settings.
|
||||
encoder_config = send_stream->GetEncoderConfig().Copy();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user