mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
Introduce a frame dumping encoder wrapper.
Expose new function MaybeCreateFrameDumpingEncoderWrapper that wraps another passed encoder and dumps its encoded frames out into a unique IVF file into the directory specified by the "WebRTC-EncoderDataDumpDirectory" field trial. If the passed encoder is nullptr, or the field trial is not setup, the function just returns the passed encoder. The directory specified by the field trial parameter should be delimited by ';'. The new function is wired up in VideoStreamEncoder. Bug: b/296242528 Change-Id: I6143adf899f78fcc03d4239a86c68dcbab483f1c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/317200 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Markus Handell <handellm@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40600}
This commit is contained in:
parent
56c34a9ff4
commit
411639ede8
5 changed files with 206 additions and 4 deletions
|
@ -163,8 +163,8 @@ bool IvfFileWriter::WriteFrame(const EncodedImage& encoded_image,
|
||||||
int64_t timestamp = using_capture_timestamps_
|
int64_t timestamp = using_capture_timestamps_
|
||||||
? encoded_image.capture_time_ms_
|
? encoded_image.capture_time_ms_
|
||||||
: wrap_handler_.Unwrap(encoded_image.Timestamp());
|
: wrap_handler_.Unwrap(encoded_image.Timestamp());
|
||||||
if (last_timestamp_ != -1 && timestamp <= last_timestamp_) {
|
if (last_timestamp_ != -1 && timestamp < last_timestamp_) {
|
||||||
RTC_LOG(LS_WARNING) << "Timestamp no increasing: " << last_timestamp_
|
RTC_LOG(LS_WARNING) << "Timestamp not increasing: " << last_timestamp_
|
||||||
<< " -> " << timestamp;
|
<< " -> " << timestamp;
|
||||||
}
|
}
|
||||||
last_timestamp_ = timestamp;
|
last_timestamp_ = timestamp;
|
||||||
|
|
|
@ -194,6 +194,32 @@ rtc_library("frame_dumping_decoder") {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtc_library("frame_dumping_encoder") {
|
||||||
|
visibility = [ "*" ]
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
"frame_dumping_encoder.cc",
|
||||||
|
"frame_dumping_encoder.h",
|
||||||
|
]
|
||||||
|
|
||||||
|
deps = [
|
||||||
|
"../api:field_trials_view",
|
||||||
|
"../api:sequence_checker",
|
||||||
|
"../api/video:encoded_frame",
|
||||||
|
"../api/video:encoded_image",
|
||||||
|
"../api/video:video_frame",
|
||||||
|
"../api/video_codecs:video_codecs_api",
|
||||||
|
"../modules/video_coding",
|
||||||
|
"../modules/video_coding:video_codec_interface",
|
||||||
|
"../modules/video_coding:video_coding_utility",
|
||||||
|
"../rtc_base:stringutils",
|
||||||
|
"../rtc_base:timeutils",
|
||||||
|
"../rtc_base/system:file_wrapper",
|
||||||
|
]
|
||||||
|
|
||||||
|
absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
|
||||||
|
}
|
||||||
|
|
||||||
rtc_library("frame_cadence_adapter") {
|
rtc_library("frame_cadence_adapter") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
sources = [
|
sources = [
|
||||||
|
@ -371,6 +397,7 @@ rtc_library("video_stream_encoder_impl") {
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":frame_cadence_adapter",
|
":frame_cadence_adapter",
|
||||||
|
":frame_dumping_encoder",
|
||||||
":video_stream_encoder_interface",
|
":video_stream_encoder_interface",
|
||||||
"../api:field_trials_view",
|
"../api:field_trials_view",
|
||||||
"../api:rtp_parameters",
|
"../api:rtp_parameters",
|
||||||
|
|
138
video/frame_dumping_encoder.cc
Normal file
138
video/frame_dumping_encoder.cc
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 "video/frame_dumping_encoder.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/algorithm/container.h"
|
||||||
|
#include "api/sequence_checker.h"
|
||||||
|
#include "api/video/video_codec_type.h"
|
||||||
|
#include "modules/video_coding/utility/ivf_file_writer.h"
|
||||||
|
#include "rtc_base/strings/string_builder.h"
|
||||||
|
#include "rtc_base/system/file_wrapper.h"
|
||||||
|
#include "rtc_base/time_utils.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kEncoderDataDumpDirectoryFieldTrial =
|
||||||
|
"WebRTC-EncoderDataDumpDirectory";
|
||||||
|
|
||||||
|
class FrameDumpingEncoder : public VideoEncoder, public EncodedImageCallback {
|
||||||
|
public:
|
||||||
|
FrameDumpingEncoder(std::unique_ptr<VideoEncoder> wrapped,
|
||||||
|
int64_t origin_time_micros,
|
||||||
|
std::string output_directory)
|
||||||
|
: wrapped_(std::move(wrapped)),
|
||||||
|
output_directory_(output_directory),
|
||||||
|
origin_time_micros_(origin_time_micros) {
|
||||||
|
sequence_checker_.Detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoEncoder overloads.
|
||||||
|
void SetFecControllerOverride(
|
||||||
|
FecControllerOverride* fec_controller_override) override {
|
||||||
|
wrapped_->SetFecControllerOverride(fec_controller_override);
|
||||||
|
}
|
||||||
|
int InitEncode(const VideoCodec* codec_settings,
|
||||||
|
const VideoEncoder::Settings& settings) override {
|
||||||
|
codec_settings_ = *codec_settings;
|
||||||
|
return wrapped_->InitEncode(codec_settings, settings);
|
||||||
|
}
|
||||||
|
int32_t RegisterEncodeCompleteCallback(
|
||||||
|
EncodedImageCallback* callback) override {
|
||||||
|
callback_ = callback;
|
||||||
|
return wrapped_->RegisterEncodeCompleteCallback(this);
|
||||||
|
}
|
||||||
|
int32_t Release() override { return wrapped_->Release(); }
|
||||||
|
int32_t Encode(const VideoFrame& frame,
|
||||||
|
const std::vector<VideoFrameType>* frame_types) override {
|
||||||
|
return wrapped_->Encode(frame, frame_types);
|
||||||
|
}
|
||||||
|
void SetRates(const RateControlParameters& parameters) override {
|
||||||
|
wrapped_->SetRates(parameters);
|
||||||
|
}
|
||||||
|
void OnPacketLossRateUpdate(float packet_loss_rate) override {
|
||||||
|
wrapped_->OnPacketLossRateUpdate(packet_loss_rate);
|
||||||
|
}
|
||||||
|
void OnRttUpdate(int64_t rtt_ms) override { wrapped_->OnRttUpdate(rtt_ms); }
|
||||||
|
void OnLossNotification(const LossNotification& loss_notification) override {
|
||||||
|
wrapped_->OnLossNotification(loss_notification);
|
||||||
|
}
|
||||||
|
EncoderInfo GetEncoderInfo() const override {
|
||||||
|
return wrapped_->GetEncoderInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodedImageCallback overrides.
|
||||||
|
Result OnEncodedImage(const EncodedImage& encoded_image,
|
||||||
|
const CodecSpecificInfo* codec_specific_info) override {
|
||||||
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||||
|
GetFileWriterForSimulcastIndex(encoded_image.SimulcastIndex().value_or(0))
|
||||||
|
.WriteFrame(encoded_image, codec_settings_.codecType);
|
||||||
|
return callback_->OnEncodedImage(encoded_image, codec_specific_info);
|
||||||
|
}
|
||||||
|
void OnDroppedFrame(DropReason reason) override {
|
||||||
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||||
|
callback_->OnDroppedFrame(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string FilenameFromSimulcastIndex(int index) {
|
||||||
|
char filename_buffer[1024];
|
||||||
|
rtc::SimpleStringBuilder builder(filename_buffer);
|
||||||
|
builder << output_directory_ << "/webrtc_encoded_frames"
|
||||||
|
<< "." << origin_time_micros_ << "." << index << ".ivf";
|
||||||
|
return builder.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
IvfFileWriter& GetFileWriterForSimulcastIndex(int index) {
|
||||||
|
const auto& it = writers_by_simulcast_index_.find(index);
|
||||||
|
if (it != writers_by_simulcast_index_.end()) {
|
||||||
|
return *it->second;
|
||||||
|
}
|
||||||
|
auto writer = IvfFileWriter::Wrap(
|
||||||
|
FileWrapper::OpenWriteOnly(FilenameFromSimulcastIndex(index)),
|
||||||
|
/*byte_limit=*/100'000'000);
|
||||||
|
auto* writer_ptr = writer.get();
|
||||||
|
writers_by_simulcast_index_.insert(
|
||||||
|
std::make_pair(index, std::move(writer)));
|
||||||
|
return *writer_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SequenceChecker sequence_checker_;
|
||||||
|
std::unique_ptr<VideoEncoder> wrapped_;
|
||||||
|
std::map<int, std::unique_ptr<IvfFileWriter>> writers_by_simulcast_index_;
|
||||||
|
std::unique_ptr<IvfFileWriter> writer_;
|
||||||
|
VideoCodec codec_settings_;
|
||||||
|
EncodedImageCallback* callback_ = nullptr;
|
||||||
|
std::string output_directory_;
|
||||||
|
int64_t origin_time_micros_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<VideoEncoder> MaybeCreateFrameDumpingEncoderWrapper(
|
||||||
|
std::unique_ptr<VideoEncoder> encoder,
|
||||||
|
const FieldTrialsView& field_trials) {
|
||||||
|
auto output_directory =
|
||||||
|
field_trials.Lookup(kEncoderDataDumpDirectoryFieldTrial);
|
||||||
|
if (output_directory.empty() || !encoder) {
|
||||||
|
return encoder;
|
||||||
|
}
|
||||||
|
absl::c_replace(output_directory, ';', '/');
|
||||||
|
return std::make_unique<FrameDumpingEncoder>(
|
||||||
|
std::move(encoder), rtc::TimeMicros(), output_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
34
video/frame_dumping_encoder.h
Normal file
34
video/frame_dumping_encoder.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 VIDEO_FRAME_DUMPING_ENCODER_H_
|
||||||
|
#define VIDEO_FRAME_DUMPING_ENCODER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "api/field_trials_view.h"
|
||||||
|
#include "api/video_codecs/video_encoder.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// Creates an encoder that wraps another passed encoder and dumps its encoded
|
||||||
|
// frames out into a unique IVF file into the directory specified by the
|
||||||
|
// "WebRTC-EncoderDataDumpDirectory" field trial. Each file generated is
|
||||||
|
// suffixed by the simulcast index of the encoded frames. If the passed encoder
|
||||||
|
// is nullptr, or the field trial is not setup, the function just returns the
|
||||||
|
// passed encoder. The directory specified by the field trial parameter should
|
||||||
|
// be delimited by ';'.
|
||||||
|
std::unique_ptr<VideoEncoder> MaybeCreateFrameDumpingEncoderWrapper(
|
||||||
|
std::unique_ptr<VideoEncoder> encoder,
|
||||||
|
const FieldTrialsView& field_trials);
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // VIDEO_FRAME_DUMPING_ENCODER_H_
|
|
@ -55,6 +55,7 @@
|
||||||
#include "video/alignment_adjuster.h"
|
#include "video/alignment_adjuster.h"
|
||||||
#include "video/config/encoder_stream_factory.h"
|
#include "video/config/encoder_stream_factory.h"
|
||||||
#include "video/frame_cadence_adapter.h"
|
#include "video/frame_cadence_adapter.h"
|
||||||
|
#include "video/frame_dumping_encoder.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
@ -950,8 +951,10 @@ void VideoStreamEncoder::ReconfigureEncoder() {
|
||||||
// supports only single instance of encoder of given type.
|
// supports only single instance of encoder of given type.
|
||||||
encoder_.reset();
|
encoder_.reset();
|
||||||
|
|
||||||
encoder_ = settings_.encoder_factory->CreateVideoEncoder(
|
encoder_ = MaybeCreateFrameDumpingEncoderWrapper(
|
||||||
encoder_config_.video_format);
|
settings_.encoder_factory->CreateVideoEncoder(
|
||||||
|
encoder_config_.video_format),
|
||||||
|
field_trials_);
|
||||||
if (!encoder_) {
|
if (!encoder_) {
|
||||||
RTC_LOG(LS_ERROR) << "CreateVideoEncoder failed, failing encoder format: "
|
RTC_LOG(LS_ERROR) << "CreateVideoEncoder failed, failing encoder format: "
|
||||||
<< encoder_config_.video_format.ToString();
|
<< encoder_config_.video_format.ToString();
|
||||||
|
|
Loading…
Reference in a new issue