File: v4l2_video_decoder_backend_stateless.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; 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,811; 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 (211 lines) | stat: -rw-r--r-- 8,407 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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATELESS_H_
#define MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATELESS_H_

#include "base/containers/lru_cache.h"
#include "base/containers/queue.h"
#include "base/containers/small_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/types/id_type.h"
#include "media/base/cdm_context.h"
#include "media/base/decoder_status.h"
#include "media/base/video_decoder.h"
#include "media/gpu/chromeos/dmabuf_video_frame_pool.h"
#include "media/gpu/v4l2/v4l2_decode_surface_handler.h"
#include "media/gpu/v4l2/v4l2_video_decoder_backend.h"

namespace media {

class AcceleratedVideoDecoder;

class V4L2StatelessVideoDecoderBackend : public V4L2VideoDecoderBackend,
                                         public V4L2DecodeSurfaceHandler {
 public:
  // Constructor for the stateless backend. Arguments are:
  // |client| the decoder we will be backing.
  // |device| the V4L2 decoder device.
  // |frame_pool| pool from which to get backing memory for decoded frames.
  // |profile| profile of the codec we will decode.
  // |task_runner| the decoder task runner, to which we will post our tasks.
  V4L2StatelessVideoDecoderBackend(
      Client* const client,
      scoped_refptr<V4L2Device> device,
      VideoCodecProfile profile,
      const VideoColorSpace& color_space,
      scoped_refptr<base::SequencedTaskRunner> task_runner,
      CdmContext* cdm_context);

  V4L2StatelessVideoDecoderBackend(const V4L2StatelessVideoDecoderBackend&) =
      delete;
  V4L2StatelessVideoDecoderBackend& operator=(
      const V4L2StatelessVideoDecoderBackend&) = delete;

  ~V4L2StatelessVideoDecoderBackend() override;

  // V4L2VideoDecoderBackend implementation
  bool Initialize() override;
  void EnqueueDecodeTask(scoped_refptr<DecoderBuffer> buffer,
                         VideoDecoder::DecodeCB decode_cb) override;
  void OnOutputBufferDequeued(V4L2ReadableBufferRef buffer) override;
  void OnStreamStopped(bool stop_input_queue) override;
  bool ApplyResolution(const gfx::Size& pic_size,
                       const gfx::Rect& visible_rect) override;
  void OnChangeResolutionDone(CroStatus status) override;
  void ClearPendingRequests(DecoderStatus status) override;
  bool StopInputQueueOnResChange() const override;
  size_t GetNumOUTPUTQueueBuffers(bool secure_mode) const override;

  // V4L2DecodeSurfaceHandler implementation.
  scoped_refptr<V4L2DecodeSurface> CreateSurface() override;
  scoped_refptr<V4L2DecodeSurface> CreateSecureSurface(
      uint64_t secure_handle) override;
  bool SubmitSlice(V4L2DecodeSurface* dec_surface,
                   const uint8_t* data,
                   size_t size) override;
  void DecodeSurface(scoped_refptr<V4L2DecodeSurface> dec_surface) override;
  void SurfaceReady(scoped_refptr<V4L2DecodeSurface> dec_surface,
                    int32_t bitstream_id,
                    const gfx::Rect& visible_rect,
                    const VideoColorSpace& color_space) override;
  void ResumeDecoding() override;

 private:
  // Request for displaying the surface or calling the decode callback.
  struct OutputRequest;

  // Request for decoding buffer. Every EnqueueDecodeTask() call generates 1
  // DecodeRequest.
  struct DecodeRequest {
    // The decode buffer passed to EnqueueDecodeTask().
    scoped_refptr<DecoderBuffer> buffer;
    // The callback function passed to EnqueueDecodeTask().
    VideoDecoder::DecodeCB decode_cb;
    // The identifier for the decoder buffer.
    int32_t bitstream_id;

    DecodeRequest(scoped_refptr<DecoderBuffer> buf,
                  VideoDecoder::DecodeCB cb,
                  int32_t id);

    DecodeRequest(const DecodeRequest&) = delete;
    DecodeRequest& operator=(const DecodeRequest&) = delete;

    // Allow move, but not copy
    DecodeRequest(DecodeRequest&&);
    DecodeRequest& operator=(DecodeRequest&&);

    ~DecodeRequest();
  };

  // The reason the decoding is paused.
  enum class PauseReason {
    // Not stopped, decoding normally.
    kNone,
    // Cannot create a new V4L2 surface. Waiting for surfaces to be released.
    kRanOutOfSurfaces,
  };

  // Callback which is called when the output buffer is not used anymore.
  static void ReuseOutputBufferThunk(
      scoped_refptr<base::SequencedTaskRunner> task_runner,
      std::optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this,
      V4L2ReadableBufferRef buffer);
  void ReuseOutputBuffer(V4L2ReadableBufferRef buffer);

  // Try to advance the decoding work.
  void DoDecodeWork();
  // Try to decode buffer from the pending decode request queue.
  // This method stops decoding when:
  // - Run out of surface
  // - Flushing or changing resolution
  // Invoke this method again when these situation ends.
  bool PumpDecodeTask();
  // Try to output surface from |output_request_queue_|.
  // This method stops outputting surface when the first surface is not dequeued
  // from the V4L2 device. Invoke this method again when any surface is
  // dequeued from the V4L2 device.
  void PumpOutputSurfaces();
  // Setup the format of V4L2 output buffer, and allocate new buffer set.
  void ChangeResolution();

  // Returns whether |profile| is supported by a v4l2 stateless decoder driver.
  bool IsSupportedProfile(VideoCodecProfile profile);

  // Create codec-specific AcceleratedVideoDecoder and reset related variables.
  bool CreateDecoder();

  // Video profile we are decoding.
  VideoCodecProfile profile_;

  // Video color space we are decoding.
  VideoColorSpace color_space_;

  // Video coded size we are decoding.
  gfx::Size pic_size_;

  // Video decoder used to parse stream headers by software.
  std::unique_ptr<AcceleratedVideoDecoder> decoder_;

  // The decode request which is currently processed.
  std::optional<DecodeRequest> current_decode_request_;
  // Surfaces enqueued to V4L2 device. Since we are stateless, they are
  // guaranteed to be proceeded in FIFO order.
  base::queue<scoped_refptr<V4L2DecodeSurface>> surfaces_at_device_;

  // Queue of pending decode request.
  base::queue<DecodeRequest> decode_request_queue_;

  // Queue of pending output request.
  base::queue<OutputRequest> output_request_queue_;

  // Indicates why decoding is currently paused.
  PauseReason pause_reason_ = PauseReason::kNone;

  // The time at which each buffer decode operation started. Not each decode
  // operation leads to a frame being output and frames might be reordered, so
  // we don't know when it's safe to drop a timestamp. This means we need to use
  // a cache here, with a size large enough to account for frame reordering.
  base::LRUCache<int32_t, base::TimeDelta> bitstream_id_to_timestamp_;

  // The task runner we are running on, for convenience.
  const scoped_refptr<base::SequencedTaskRunner> task_runner_;

  // Callbacks of EOS buffer passed from Decode().
  VideoDecoder::DecodeCB flush_cb_;

  // VideoCodecProfiles supported by a v4l2 stateless decoder driver.
  std::vector<VideoCodecProfile> supported_profiles_;

  // Reference to request queue to get free requests.
  raw_ptr<V4L2RequestsQueue> requests_queue_;

  // Map of enqueuing timestamps to wall clock, for histogramming purposes.
  base::small_map<std::map<int64_t, base::TimeTicks>> enqueuing_timestamps_;
  // Same but with ScopedDecodeTrace for chrome:tracing purposes.
  base::small_map<std::map<base::TimeDelta, std::unique_ptr<ScopedDecodeTrace>>>
      buffer_tracers_ GUARDED_BY_CONTEXT(sequence_checker_);

  // Int32 safe ID generator, starting at 0. Generated IDs are used to uniquely
  // identify a Decode() request for stateless backends. BitstreamID is just
  // a "phantom type" (see StrongAlias), essentially just a name.
  struct BitstreamID {};
  base::IdType32<BitstreamID>::Generator bitstream_id_generator_
      GUARDED_BY_CONTEXT(sequence_checker_);

  raw_ptr<CdmContext> cdm_context_;

  base::WeakPtr<V4L2StatelessVideoDecoderBackend> weak_this_;
  base::WeakPtrFactory<V4L2StatelessVideoDecoderBackend> weak_this_factory_{
      this};
};

}  // namespace media

#endif  // MEDIA_GPU_V4L2_V4L2_VIDEO_DECODER_BACKEND_STATELESS_H_