forked from webrtc-sdk/webrtc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PCLF] Add video writer which accounts for freezes
Bug: b/237997865 Change-Id: I6d6e3faa48e6bddbe298ead7b1350dd3c70481b2 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/268545 Reviewed-by: Mirko Bonadei <[email protected]> Reviewed-by: Ilya Nikolaevskiy <[email protected]> Commit-Queue: Artem Titov <[email protected]> Cr-Commit-Position: refs/heads/main@{#37543}
- Loading branch information
Artem Titov
authored and
WebRTC LUCI CQ
committed
Jul 18, 2022
1 parent
3e378d7
commit e4bda7d
Showing
4 changed files
with
554 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
test/testsupport/fixed_fps_video_frame_writer_adapter.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by a BSD-style license | ||
* that can be found in the LICENSE file in the root of the source | ||
* tree. An additional intellectual property rights grant can be found | ||
* in the file PATENTS. All contributing project authors may | ||
* be found in the AUTHORS file in the root of the source tree. | ||
*/ | ||
|
||
#include "test/testsupport/fixed_fps_video_frame_writer_adapter.h" | ||
|
||
#include <cmath> | ||
#include <utility> | ||
|
||
#include "absl/types/optional.h" | ||
#include "api/units/time_delta.h" | ||
#include "api/video/video_sink_interface.h" | ||
#include "rtc_base/checks.h" | ||
#include "test/testsupport/video_frame_writer.h" | ||
|
||
namespace webrtc { | ||
namespace test { | ||
namespace { | ||
|
||
constexpr TimeDelta kOneSecond = TimeDelta::Seconds(1); | ||
|
||
} // namespace | ||
|
||
FixedFpsVideoFrameWriterAdapter::FixedFpsVideoFrameWriterAdapter( | ||
int fps, | ||
Clock* clock, | ||
std::unique_ptr<VideoFrameWriter> delegate) | ||
: inter_frame_interval_(kOneSecond / fps), | ||
clock_(clock), | ||
delegate_(std::move(delegate)) {} | ||
|
||
FixedFpsVideoFrameWriterAdapter::~FixedFpsVideoFrameWriterAdapter() { | ||
Close(); | ||
} | ||
|
||
void FixedFpsVideoFrameWriterAdapter::Close() { | ||
if (is_closed_) { | ||
return; | ||
} | ||
is_closed_ = true; | ||
if (!last_frame_.has_value()) { | ||
return; | ||
} | ||
Timestamp now = Now(); | ||
RTC_CHECK(WriteMissedSlotsExceptLast(now)); | ||
RTC_CHECK(delegate_->WriteFrame(*last_frame_)); | ||
delegate_->Close(); | ||
} | ||
|
||
bool FixedFpsVideoFrameWriterAdapter::WriteFrame(const VideoFrame& frame) { | ||
RTC_CHECK(!is_closed_); | ||
Timestamp now = Now(); | ||
if (!last_frame_.has_value()) { | ||
RTC_CHECK(!last_frame_time_.IsFinite()); | ||
last_frame_ = frame; | ||
last_frame_time_ = now; | ||
return true; | ||
} | ||
|
||
RTC_CHECK(last_frame_time_.IsFinite()); | ||
|
||
if (last_frame_time_ > now) { | ||
// New frame was recevied before expected time "slot" for current | ||
// `last_frame_` came => just replace current `last_frame_` with | ||
// received `frame`. | ||
RTC_CHECK_LE(last_frame_time_ - now, inter_frame_interval_ / 2); | ||
last_frame_ = frame; | ||
return true; | ||
} | ||
|
||
if (!WriteMissedSlotsExceptLast(now)) { | ||
return false; | ||
} | ||
|
||
if (now - last_frame_time_ < inter_frame_interval_ / 2) { | ||
// New frame was received closer to the expected time "slot" for current | ||
// `last_frame_` than to the next "slot" => just replace current | ||
// `last_frame_` with received `frame`. | ||
last_frame_ = frame; | ||
return true; | ||
} | ||
|
||
if (!delegate_->WriteFrame(*last_frame_)) { | ||
return false; | ||
} | ||
last_frame_ = frame; | ||
last_frame_time_ = last_frame_time_ + inter_frame_interval_; | ||
return true; | ||
} | ||
|
||
bool FixedFpsVideoFrameWriterAdapter::WriteMissedSlotsExceptLast( | ||
Timestamp now) { | ||
RTC_CHECK(last_frame_time_.IsFinite()); | ||
while (now - last_frame_time_ > inter_frame_interval_) { | ||
if (!delegate_->WriteFrame(*last_frame_)) { | ||
return false; | ||
} | ||
last_frame_time_ = last_frame_time_ + inter_frame_interval_; | ||
} | ||
return true; | ||
} | ||
|
||
Timestamp FixedFpsVideoFrameWriterAdapter::Now() const { | ||
return clock_->CurrentTime(); | ||
} | ||
|
||
} // namespace test | ||
} // namespace webrtc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. | ||
* | ||
* Use of this source code is governed by a BSD-style license | ||
* that can be found in the LICENSE file in the root of the source | ||
* tree. An additional intellectual property rights grant can be found | ||
* in the file PATENTS. All contributing project authors may | ||
* be found in the AUTHORS file in the root of the source tree. | ||
*/ | ||
|
||
#ifndef TEST_TESTSUPPORT_FIXED_FPS_VIDEO_FRAME_WRITER_ADAPTER_H_ | ||
#define TEST_TESTSUPPORT_FIXED_FPS_VIDEO_FRAME_WRITER_ADAPTER_H_ | ||
|
||
#include <memory> | ||
|
||
#include "absl/types/optional.h" | ||
#include "api/video/video_sink_interface.h" | ||
#include "system_wrappers/include/clock.h" | ||
#include "test/testsupport/video_frame_writer.h" | ||
|
||
namespace webrtc { | ||
namespace test { | ||
|
||
// Writes video to the specified video writer with specified fixed frame rate. | ||
// If at the point in time X no new frames are passed to the writer, the | ||
// previous frame is used to fill the gap and preserve frame rate. | ||
// | ||
// This adaptor uses next algorithm: | ||
// There are output "slots" at a fixed frame rate (starting at the time of the | ||
// first received frame). Each incoming frame is assigned to the closest output | ||
// slot. Then empty slots are filled by repeating the closest filled slot before | ||
// empty one. If there are multiple frames closest to the same slot, the latest | ||
// received one is used. | ||
// | ||
// The frames are outputted for the whole duration of the class life after the | ||
// first frame was written or until it will be closed. | ||
// | ||
// For example if frames from A to F were received, then next output sequence | ||
// will be generated: | ||
// Received frames: A B C D EF Destructor called | ||
// | | | | || | | ||
// v v v v vv v | ||
// X----X----X----X----X----X----X----X----X----+----+-- | ||
// | | | | | | | | | | ||
// Produced frames: A A A B C C F F F | ||
// | ||
// This class is not thread safe. | ||
class FixedFpsVideoFrameWriterAdapter : public VideoFrameWriter { | ||
public: | ||
FixedFpsVideoFrameWriterAdapter(int fps, | ||
Clock* clock, | ||
std::unique_ptr<VideoFrameWriter> delegate); | ||
~FixedFpsVideoFrameWriterAdapter() override; | ||
|
||
bool WriteFrame(const webrtc::VideoFrame& frame) override; | ||
|
||
// Closes adapter and underlying delegate. User mustn't call to the WriteFrame | ||
// after calling this method. | ||
void Close() override; | ||
|
||
private: | ||
// Writes `last_frame_` for each "slot" from `last_frame_time_` up to now | ||
// excluding the last one. | ||
// Updates `last_frame_time_` to the position of the last NOT WRITTEN frame. | ||
// Returns true if all writes were successful, otherwise retuns false. In such | ||
// case it is not guranteed how many frames were actually written. | ||
bool WriteMissedSlotsExceptLast(Timestamp now); | ||
Timestamp Now() const; | ||
|
||
// Because `TimeDelta` stores time with microseconds precision | ||
// `last_frame_time_` may have a small drift and for very long streams it | ||
// must be updated to use double for time. | ||
const TimeDelta inter_frame_interval_; | ||
Clock* const clock_; | ||
std::unique_ptr<VideoFrameWriter> delegate_; | ||
bool is_closed_ = false; | ||
|
||
// Expected time slot for the last frame. | ||
Timestamp last_frame_time_ = Timestamp::MinusInfinity(); | ||
absl::optional<VideoFrame> last_frame_ = absl::nullopt; | ||
}; | ||
|
||
} // namespace test | ||
} // namespace webrtc | ||
|
||
#endif // TEST_TESTSUPPORT_FIXED_FPS_VIDEO_FRAME_WRITER_ADAPTER_H_ |
Oops, something went wrong.