File: stats_collecting_decoder.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (166 lines) | stat: -rw-r--r-- 5,954 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/peerconnection/stats_collecting_decoder.h"

#include <algorithm>
#include <atomic>

#include "base/check.h"
#include "base/logging.h"
#include "media/base/video_codecs.h"
#include "third_party/blink/renderer/platform/webrtc/webrtc_video_utils.h"
#include "third_party/webrtc/modules/video_coding/include/video_error_codes.h"

namespace blink {
namespace {
// Limit data collection to when only a single decoder is active. This gives an
// optimistic estimate of the performance.
constexpr int kMaximumDecodersToCollectStats = 1;
constexpr base::TimeDelta kCheckSimultaneousDecodersInterval = base::Seconds(5);

// Number of StatsCollectingDecoder instances right now that have started
// decoding.
std::atomic_int* GetDecoderCounter() {
  static std::atomic_int s_counter(0);
  return &s_counter;
}
}  // namespace

StatsCollectingDecoder::StatsCollectingDecoder(
    const webrtc::SdpVideoFormat& format,
    std::unique_ptr<webrtc::VideoDecoder> decoder,
    StatsCollectingDecoder::StoreProcessingStatsCB stats_callback)
    : StatsCollector(
          /*is_decode=*/true,
          WebRtcVideoFormatToMediaVideoCodecProfile(format),
          stats_callback),
      decoder_(std::move(decoder)) {
  DVLOG(3) << __func__;
  CHECK(decoder_);
  DETACH_FROM_SEQUENCE(decoding_sequence_checker_);
}

StatsCollectingDecoder::~StatsCollectingDecoder() {
  DVLOG(3) << __func__;
}

// Implementation of webrtc::VideoDecoder.
bool StatsCollectingDecoder::Configure(const Settings& settings) {
  DVLOG(3) << __func__;
  DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
  return decoder_->Configure(settings);
}

int32_t StatsCollectingDecoder::Decode(const webrtc::EncodedImage& input_image,
                                       bool missing_frames,
                                       int64_t render_time_ms) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
  if (!first_frame_decoded_) {
    first_frame_decoded_ = true;
    ++(*GetDecoderCounter());
  }
  {
    base::AutoLock auto_lock(lock_);
    number_of_new_keyframes_ +=
        input_image._frameType == webrtc::VideoFrameType::kVideoFrameKey;
  }
  return decoder_->Decode(input_image, missing_frames, render_time_ms);
}

int32_t StatsCollectingDecoder::RegisterDecodeCompleteCallback(
    DecodedImageCallback* callback) {
  DVLOG(3) << __func__;
  DCHECK_CALLED_ON_VALID_SEQUENCE(decoding_sequence_checker_);
  decoded_callback_ = callback;
  return decoder_->RegisterDecodeCompleteCallback(this);
}

int32_t StatsCollectingDecoder::Release() {
  // Release is called after decode_sequence has been stopped.
  DVLOG(3) << __func__;
  int32_t ret = decoder_->Release();

  // There will be no new calls to Decoded() after the call to
  // decoder_->Release(). Any outstanding calls to Decoded() will also finish
  // before decoder_->Release() returns. It's therefore safe to access member
  // variables here.
  if (active_stats_collection() &&
      samples_collected() >= kMinSamplesThreshold) {
    ReportStats();
  }

  if (first_frame_decoded_) {
    --(*GetDecoderCounter());
    first_frame_decoded_ = false;
  }

  return ret;
}

webrtc::VideoDecoder::DecoderInfo StatsCollectingDecoder::GetDecoderInfo()
    const {
  return decoder_->GetDecoderInfo();
}

// Implementation of webrtc::DecodedImageCallback.
int32_t StatsCollectingDecoder::Decoded(webrtc::VideoFrame& decodedImage) {
  Decoded(decodedImage, std::nullopt, std::nullopt);
  return WEBRTC_VIDEO_CODEC_OK;
}

void StatsCollectingDecoder::Decoded(webrtc::VideoFrame& decodedImage,
                                     std::optional<int32_t> decode_time_ms,
                                     std::optional<uint8_t> qp) {
  // Decoded may be called on either the decoding sequence (SW decoding) or
  // media sequence (HW decoding). However, these calls are not happening at the
  // same time. If there's a fallback from SW decoding to HW decoding, a call to
  // HW decoder->Release() ensures that any potential callbacks on the media
  // sequence are finished before the decoding continues on the decoding
  // sequence.
  DCHECK(decoded_callback_);
  decoded_callback_->Decoded(decodedImage, decode_time_ms, qp);
  if (stats_collection_finished()) {
    // Return early if we've already finished the stats collection.
    return;
  }

  base::TimeTicks now = base::TimeTicks::Now();
  // Verify that there's only a single decoder when data collection is taking
  // place.
  if ((now - last_check_for_simultaneous_decoders_) >
      kCheckSimultaneousDecodersInterval) {
    last_check_for_simultaneous_decoders_ = now;
    DVLOG(3) << "Simultaneous decoders: " << *GetDecoderCounter();
    if (active_stats_collection()) {
      if (*GetDecoderCounter() > kMaximumDecodersToCollectStats) {
        // Too many decoders, cancel stats collection.
        ClearStatsCollection();
      }
    } else if (*GetDecoderCounter() <= kMaximumDecodersToCollectStats) {
      // Start up stats collection since there's only a single decoder active.
      StartStatsCollection();
    }
  }

  // Read out number of new processed keyframes since last Decoded() callback.
  size_t number_of_new_keyframes = 0;
  {
    base::AutoLock auto_lock(lock_);
    number_of_new_keyframes += number_of_new_keyframes_;
    number_of_new_keyframes_ = 0;
  }

  if (active_stats_collection() && decodedImage.processing_time()) {
    int pixel_size = static_cast<int>(decodedImage.size());
    bool is_hardware_accelerated =
        decoder_->GetDecoderInfo().is_hardware_accelerated;
    float processing_time_ms = decodedImage.processing_time()->Elapsed().ms();

    AddProcessingTime(pixel_size, is_hardware_accelerated, processing_time_ms,
                      number_of_new_keyframes, now);
  }
}

}  // namespace blink