blob: cb9c576f4ef3ba06abc0f1b1d0b1ed1ef704a171 [file] [log] [blame]
Markus Handell411639e2023-08-22 10:58:471/*
2 * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "video/frame_dumping_encoder.h"
12
13#include <map>
14#include <string>
15#include <utility>
16#include <vector>
17
18#include "absl/algorithm/container.h"
19#include "api/sequence_checker.h"
20#include "api/video/video_codec_type.h"
21#include "modules/video_coding/utility/ivf_file_writer.h"
22#include "rtc_base/strings/string_builder.h"
23#include "rtc_base/system/file_wrapper.h"
24#include "rtc_base/time_utils.h"
25
26namespace webrtc {
27namespace {
28
29constexpr auto kEncoderDataDumpDirectoryFieldTrial =
30 "WebRTC-EncoderDataDumpDirectory";
31
32class FrameDumpingEncoder : public VideoEncoder, public EncodedImageCallback {
33 public:
34 FrameDumpingEncoder(std::unique_ptr<VideoEncoder> wrapped,
35 int64_t origin_time_micros,
36 std::string output_directory)
37 : wrapped_(std::move(wrapped)),
38 output_directory_(output_directory),
Markus Handell1692e542023-08-23 10:44:1839 origin_time_micros_(origin_time_micros) {}
40
41 ~FrameDumpingEncoder() override {
42 MutexLock lock(&mu_);
43 writers_by_simulcast_index_.clear();
Markus Handell411639e2023-08-22 10:58:4744 }
45
46 // VideoEncoder overloads.
47 void SetFecControllerOverride(
48 FecControllerOverride* fec_controller_override) override {
49 wrapped_->SetFecControllerOverride(fec_controller_override);
50 }
51 int InitEncode(const VideoCodec* codec_settings,
52 const VideoEncoder::Settings& settings) override {
53 codec_settings_ = *codec_settings;
54 return wrapped_->InitEncode(codec_settings, settings);
55 }
56 int32_t RegisterEncodeCompleteCallback(
57 EncodedImageCallback* callback) override {
58 callback_ = callback;
59 return wrapped_->RegisterEncodeCompleteCallback(this);
60 }
61 int32_t Release() override { return wrapped_->Release(); }
62 int32_t Encode(const VideoFrame& frame,
63 const std::vector<VideoFrameType>* frame_types) override {
64 return wrapped_->Encode(frame, frame_types);
65 }
66 void SetRates(const RateControlParameters& parameters) override {
67 wrapped_->SetRates(parameters);
68 }
69 void OnPacketLossRateUpdate(float packet_loss_rate) override {
70 wrapped_->OnPacketLossRateUpdate(packet_loss_rate);
71 }
72 void OnRttUpdate(int64_t rtt_ms) override { wrapped_->OnRttUpdate(rtt_ms); }
73 void OnLossNotification(const LossNotification& loss_notification) override {
74 wrapped_->OnLossNotification(loss_notification);
75 }
76 EncoderInfo GetEncoderInfo() const override {
77 return wrapped_->GetEncoderInfo();
78 }
79
80 // EncodedImageCallback overrides.
81 Result OnEncodedImage(const EncodedImage& encoded_image,
82 const CodecSpecificInfo* codec_specific_info) override {
Markus Handell1692e542023-08-23 10:44:1883 {
84 MutexLock lock(&mu_);
85 GetFileWriterForSimulcastIndex(encoded_image.SimulcastIndex().value_or(0))
86 .WriteFrame(encoded_image, codec_settings_.codecType);
87 }
Markus Handell411639e2023-08-22 10:58:4788 return callback_->OnEncodedImage(encoded_image, codec_specific_info);
89 }
90 void OnDroppedFrame(DropReason reason) override {
Markus Handell411639e2023-08-22 10:58:4791 callback_->OnDroppedFrame(reason);
92 }
93
94 private:
Markus Handell1692e542023-08-23 10:44:1895 std::string FilenameFromSimulcastIndex(int index)
96 RTC_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
Markus Handell411639e2023-08-22 10:58:4797 char filename_buffer[1024];
98 rtc::SimpleStringBuilder builder(filename_buffer);
99 builder << output_directory_ << "/webrtc_encoded_frames"
100 << "." << origin_time_micros_ << "." << index << ".ivf";
101 return builder.str();
102 }
103
Markus Handell1692e542023-08-23 10:44:18104 IvfFileWriter& GetFileWriterForSimulcastIndex(int index)
105 RTC_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
Markus Handell411639e2023-08-22 10:58:47106 const auto& it = writers_by_simulcast_index_.find(index);
107 if (it != writers_by_simulcast_index_.end()) {
108 return *it->second;
109 }
110 auto writer = IvfFileWriter::Wrap(
111 FileWrapper::OpenWriteOnly(FilenameFromSimulcastIndex(index)),
112 /*byte_limit=*/100'000'000);
113 auto* writer_ptr = writer.get();
114 writers_by_simulcast_index_.insert(
115 std::make_pair(index, std::move(writer)));
116 return *writer_ptr;
117 }
118
Markus Handell411639e2023-08-22 10:58:47119 std::unique_ptr<VideoEncoder> wrapped_;
Markus Handell1692e542023-08-23 10:44:18120 Mutex mu_;
121 std::map<int, std::unique_ptr<IvfFileWriter>> writers_by_simulcast_index_
122 RTC_GUARDED_BY(mu_);
Markus Handell411639e2023-08-22 10:58:47123 VideoCodec codec_settings_;
124 EncodedImageCallback* callback_ = nullptr;
125 std::string output_directory_;
126 int64_t origin_time_micros_ = 0;
127};
128
129} // namespace
130
131std::unique_ptr<VideoEncoder> MaybeCreateFrameDumpingEncoderWrapper(
132 std::unique_ptr<VideoEncoder> encoder,
133 const FieldTrialsView& field_trials) {
134 auto output_directory =
135 field_trials.Lookup(kEncoderDataDumpDirectoryFieldTrial);
136 if (output_directory.empty() || !encoder) {
137 return encoder;
138 }
139 absl::c_replace(output_directory, ';', '/');
140 return std::make_unique<FrameDumpingEncoder>(
141 std::move(encoder), rtc::TimeMicros(), output_directory);
142}
143
144} // namespace webrtc