[PCLF] Introduce export_frame_ids option for video dump

Bug: b/240540206
Change-Id: I2d09be585804aa38b0bbc9e7b34dcd8f91f58846
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/270425
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37675}
This commit is contained in:
Artem Titov 2022-08-03 13:22:48 +02:00 committed by WebRTC LUCI CQ
parent 4c269322d6
commit d2209256ab
4 changed files with 149 additions and 8 deletions

View File

@ -125,10 +125,19 @@ std::string PeerConnectionE2EQualityTestFixture::VideoSubscription::ToString()
PeerConnectionE2EQualityTestFixture::VideoDumpOptions::VideoDumpOptions(
absl::string_view output_directory,
int sampling_modulo)
: output_directory_(output_directory), sampling_modulo_(sampling_modulo) {
int sampling_modulo,
bool export_frame_ids)
: output_directory_(output_directory),
sampling_modulo_(sampling_modulo),
export_frame_ids_(export_frame_ids) {
RTC_CHECK_GT(sampling_modulo, 0);
}
PeerConnectionE2EQualityTestFixture::VideoDumpOptions::VideoDumpOptions(
absl::string_view output_directory,
bool export_frame_ids)
: VideoDumpOptions(output_directory,
kDefaultSamplingModulo,
export_frame_ids) {}
std::string
PeerConnectionE2EQualityTestFixture::VideoDumpOptions::GetInputDumpFileName(
@ -138,6 +147,15 @@ PeerConnectionE2EQualityTestFixture::VideoDumpOptions::GetInputDumpFileName(
return test::JoinFilename(output_directory_, file_name.Release());
}
absl::optional<std::string> PeerConnectionE2EQualityTestFixture::
VideoDumpOptions::GetInputFrameIdsDumpFileName(
absl::string_view stream_label) const {
if (!export_frame_ids_) {
return absl::nullopt;
}
return GetInputDumpFileName(stream_label) + ".frame_ids.txt";
}
std::string
PeerConnectionE2EQualityTestFixture::VideoDumpOptions::GetOutputDumpFileName(
absl::string_view stream_label,
@ -147,6 +165,16 @@ PeerConnectionE2EQualityTestFixture::VideoDumpOptions::GetOutputDumpFileName(
return test::JoinFilename(output_directory_, file_name.Release());
}
absl::optional<std::string> PeerConnectionE2EQualityTestFixture::
VideoDumpOptions::GetOutputFrameIdsDumpFileName(
absl::string_view stream_label,
absl::string_view receiver) const {
if (!export_frame_ids_) {
return absl::nullopt;
}
return GetOutputDumpFileName(stream_label, receiver) + ".frame_ids.txt";
}
PeerConnectionE2EQualityTestFixture::VideoConfig::VideoConfig(
const VideoResolution& resolution)
: width(resolution.width()),

View File

@ -219,6 +219,8 @@ class PeerConnectionE2EQualityTestFixture {
class VideoDumpOptions {
public:
static constexpr int kDefaultSamplingModulo = 1;
// output_directory - the output directory where stream will be dumped. The
// output files' names will be constructed as
// <stream_name>_<receiver_name>.<extension> for output dumps and
@ -227,8 +229,16 @@ class PeerConnectionE2EQualityTestFixture {
// sampling_modulo - the module for the video frames to be dumped. Modulo
// equals X means every Xth frame will be written to the dump file. The
// value must be greater than 0. (Default: 1)
// export_frame_ids - specifies if frame ids should be exported together
// with content of the stream. If true, an output file with the same name as
// video dump and suffix ".frame_ids.txt" will be created. It will contain
// the frame ids in the same order as original frames in the output
// file with stream content. File will contain one frame id per line.
// (Default: false)
explicit VideoDumpOptions(absl::string_view output_directory,
int sampling_modulo = 1);
int sampling_modulo = kDefaultSamplingModulo,
bool export_frame_ids = false);
VideoDumpOptions(absl::string_view output_directory, bool export_frame_ids);
VideoDumpOptions(const VideoDumpOptions&) = default;
VideoDumpOptions& operator=(const VideoDumpOptions&) = default;
@ -237,14 +247,25 @@ class PeerConnectionE2EQualityTestFixture {
std::string output_directory() const { return output_directory_; }
int sampling_modulo() const { return sampling_modulo_; }
bool export_frame_ids() const { return export_frame_ids_; }
std::string GetInputDumpFileName(absl::string_view stream_label) const;
// Returns file name for input frame ids dump if `export_frame_ids()` is
// true, absl::nullopt otherwise.
absl::optional<std::string> GetInputFrameIdsDumpFileName(
absl::string_view stream_label) const;
std::string GetOutputDumpFileName(absl::string_view stream_label,
absl::string_view receiver) const;
// Returns file name for output frame ids dump if `export_frame_ids()` is
// true, absl::nullopt otherwise.
absl::optional<std::string> GetOutputFrameIdsDumpFileName(
absl::string_view stream_label,
absl::string_view receiver) const;
private:
std::string output_directory_;
int sampling_modulo_ = 1;
bool export_frame_ids_ = false;
};
// Contains properties of single video stream.

View File

@ -10,6 +10,8 @@
#include "test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h"
#include <stdio.h>
#include <utility>
#include <vector>
@ -87,6 +89,46 @@ class AnalyzingFramePreprocessor
} // namespace
VideoQualityAnalyzerInjectionHelper::VideoFrameIdsWriter::VideoFrameIdsWriter(
absl::string_view file_name)
: file_name_(file_name) {
output_file_ = fopen(file_name_.c_str(), "wb");
RTC_CHECK(output_file_ != nullptr)
<< "Failed to open file to dump frame ids for writing: " << file_name_;
}
VideoQualityAnalyzerInjectionHelper::VideoFrameIdsWriter::
~VideoFrameIdsWriter() {
fclose(output_file_);
}
void VideoQualityAnalyzerInjectionHelper::VideoFrameIdsWriter::WriteFrameId(
uint16_t frame_id) {
int chars_written = fprintf(output_file_, "%d\n", frame_id);
RTC_CHECK_GE(chars_written, 2)
<< "Failed to write frame id to the output file: " << file_name_;
}
VideoQualityAnalyzerInjectionHelper::VideoWriter2::VideoWriter2(
test::VideoFrameWriter* video_writer,
VideoFrameIdsWriter* frame_ids_writer,
int sampling_modulo)
: video_writer_(video_writer),
frame_ids_writer_(frame_ids_writer),
sampling_modulo_(sampling_modulo) {}
void VideoQualityAnalyzerInjectionHelper::VideoWriter2::OnFrame(
const VideoFrame& frame) {
if (frames_counter_++ % sampling_modulo_ != 0) {
return;
}
bool result = video_writer_->WriteFrame(frame);
RTC_CHECK(result) << "Failed to write frame";
if (frame_ids_writer_) {
frame_ids_writer_->WriteFrameId(frame.id());
}
}
VideoQualityAnalyzerInjectionHelper::VideoQualityAnalyzerInjectionHelper(
Clock* clock,
std::unique_ptr<VideoQualityAnalyzerInterface> analyzer,
@ -132,10 +174,19 @@ VideoQualityAnalyzerInjectionHelper::CreateFramePreprocessor(
if (config.input_dump_options.has_value()) {
// Using new API for video dumping.
writer = MaybeCreateVideoWriter(
config.input_dump_options->GetInputDumpFileName(peer_name), config);
config.input_dump_options->GetInputDumpFileName(*config.stream_label),
config);
RTC_CHECK(writer);
sinks.push_back(std::make_unique<VideoWriter>(
writer, config.input_dump_options->sampling_modulo()));
VideoFrameIdsWriter* frame_ids_writer = nullptr;
if (config.input_dump_options->export_frame_ids()) {
frame_ids_writers_.push_back(std::make_unique<VideoFrameIdsWriter>(
*config.input_dump_options->GetInputFrameIdsDumpFileName(
*config.stream_label)));
frame_ids_writer = frame_ids_writers_.back().get();
}
sinks.push_back(std::make_unique<VideoWriter2>(
writer, frame_ids_writer,
config.input_dump_options->sampling_modulo()));
} else {
// Using old API. To be removed.
writer = MaybeCreateVideoWriter(config.input_dump_file_name, config);
@ -202,6 +253,7 @@ void VideoQualityAnalyzerInjectionHelper::Stop() {
video_writer->Close();
}
video_writers_.clear();
frame_ids_writers_.clear();
}
test::VideoFrameWriter*
@ -275,8 +327,16 @@ VideoQualityAnalyzerInjectionHelper::PopulateSinks(
receiver_stream.stream_label, receiver_stream.peer_name),
config);
RTC_CHECK(writer);
sinks.push_back(std::make_unique<VideoWriter>(
writer, config.output_dump_options->sampling_modulo()));
VideoFrameIdsWriter* frame_ids_writer = nullptr;
if (config.output_dump_options->export_frame_ids()) {
frame_ids_writers_.push_back(std::make_unique<VideoFrameIdsWriter>(
*config.output_dump_options->GetOutputFrameIdsDumpFileName(
receiver_stream.stream_label, receiver_stream.peer_name)));
frame_ids_writer = frame_ids_writers_.back().get();
}
sinks.push_back(std::make_unique<VideoWriter2>(
writer, frame_ids_writer,
config.output_dump_options->sampling_modulo()));
} else {
// Using old API. To be removed.
absl::optional<std::string> output_dump_file_name =

View File

@ -11,6 +11,8 @@
#ifndef TEST_PC_E2E_ANALYZER_VIDEO_VIDEO_QUALITY_ANALYZER_INJECTION_HELPER_H_
#define TEST_PC_E2E_ANALYZER_VIDEO_VIDEO_QUALITY_ANALYZER_INJECTION_HELPER_H_
#include <stdio.h>
#include <map>
#include <memory>
#include <string>
@ -131,6 +133,35 @@ class VideoQualityAnalyzerInjectionHelper : public StatsObserverInterface {
}
};
class VideoFrameIdsWriter {
public:
explicit VideoFrameIdsWriter(absl::string_view file_name);
~VideoFrameIdsWriter();
void WriteFrameId(uint16_t frame_id);
private:
const std::string file_name_;
FILE* output_file_;
};
class VideoWriter2 final : public rtc::VideoSinkInterface<VideoFrame> {
public:
VideoWriter2(test::VideoFrameWriter* video_writer,
VideoFrameIdsWriter* frame_ids_writer,
int sampling_modulo);
~VideoWriter2() override = default;
void OnFrame(const VideoFrame& frame) override;
private:
test::VideoFrameWriter* const video_writer_;
VideoFrameIdsWriter* const frame_ids_writer_;
const int sampling_modulo_;
int64_t frames_counter_ = 0;
};
test::VideoFrameWriter* MaybeCreateVideoWriter(
absl::optional<std::string> file_name,
const PeerConnectionE2EQualityTestFixture::VideoConfig& config);
@ -146,6 +177,7 @@ class VideoQualityAnalyzerInjectionHelper : public StatsObserverInterface {
EncodedImageDataExtractor* extractor_;
std::vector<std::unique_ptr<test::VideoFrameWriter>> video_writers_;
std::vector<std::unique_ptr<VideoFrameIdsWriter>> frame_ids_writers_;
Mutex mutex_;
int peers_count_ RTC_GUARDED_BY(mutex_);