summaryrefslogtreecommitdiff
path: root/chromium/media/gpu/vaapi/vaapi_video_decoder.h
blob: f953716dfbef5d28fd41218aa9adb8ee26d31a8f (plain)
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_VAAPI_VAAPI_VIDEO_DECODER_H_
#define MEDIA_GPU_VAAPI_VAAPI_VIDEO_DECODER_H_

#include <stdint.h>
#include <va/va.h>

#include <map>
#include <memory>
#include <utility>

#include "base/containers/mru_cache.h"
#include "base/containers/queue.h"
#include "base/containers/small_map.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/chromeos_buildflags.h"
#include "media/base/callback_registry.h"
#include "media/base/cdm_context.h"
#include "media/base/status.h"
#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_aspect_ratio.h"
#include "media/base/video_codecs.h"
#include "media/base/video_frame_layout.h"
#include "media/gpu/chromeos/video_decoder_pipeline.h"
#include "media/gpu/decode_surface_handler.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/hdr_metadata.h"

namespace media {

class AcceleratedVideoDecoder;
class VaapiVideoDecoderDelegate;
class DmabufVideoFramePool;
class VaapiWrapper;
class VideoFrame;
class VASurface;

class VaapiVideoDecoder : public VideoDecoderMixin,
                          public DecodeSurfaceHandler<VASurface> {
 public:
  static std::unique_ptr<VideoDecoderMixin> Create(
      std::unique_ptr<MediaLog> media_log,
      scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
      base::WeakPtr<VideoDecoderMixin::Client> client);

  static absl::optional<SupportedVideoDecoderConfigs> GetSupportedConfigs();

  // VideoDecoderMixin implementation, VideoDecoder part.
  void Initialize(const VideoDecoderConfig& config,
                  bool low_delay,
                  CdmContext* cdm_context,
                  InitCB init_cb,
                  const OutputCB& output_cb,
                  const WaitingCB& waiting_cb) override;
  void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
  void Reset(base::OnceClosure reset_cb) override;
  bool NeedsBitstreamConversion() const override;
  bool CanReadWithoutStalling() const override;
  int GetMaxDecodeRequests() const override;
  VideoDecoderType GetDecoderType() const override;
  bool IsPlatformDecoder() const override;
  // VideoDecoderMixin implementation, specific part.
  void ApplyResolutionChange() override;
  bool NeedsTranscryption() override;

  // DecodeSurfaceHandler<VASurface> implementation.
  scoped_refptr<VASurface> CreateSurface() override;
  void SurfaceReady(scoped_refptr<VASurface> va_surface,
                    int32_t buffer_id,
                    const gfx::Rect& visible_rect,
                    const VideoColorSpace& color_space) override;

 private:
  // Decode task holding single decode request.
  struct DecodeTask {
    DecodeTask(scoped_refptr<DecoderBuffer> buffer,
               int32_t buffer_id,
               DecodeCB decode_done_cb);
    ~DecodeTask();
    DecodeTask(DecodeTask&&);
    DecodeTask& operator=(DecodeTask&&) = default;
    scoped_refptr<DecoderBuffer> buffer_;
    int32_t buffer_id_ = -1;
    DecodeCB decode_done_cb_;
    DISALLOW_COPY_AND_ASSIGN(DecodeTask);
  };

  enum class State {
    kUninitialized,        // not initialized yet or initialization failed.
    kWaitingForInput,      // waiting for input buffers.
    kWaitingForOutput,     // waiting for output buffers.
    kWaitingForProtected,  // waiting on something related to protected content,
                           // either setup, full sample parsing or key loading.
    kDecoding,             // decoding buffers.
    kChangingResolution,   // need to change resolution, waiting for pipeline to
                           // be flushed.
    kExpectingReset,       // resolution change is aborted, waiting for decoder
                           // to be reset.
    kResetting,            // resetting decoder.
    kError,                // decoder encountered an error.
  };

  VaapiVideoDecoder(
      std::unique_ptr<MediaLog> media_log,
      scoped_refptr<base::SequencedTaskRunner> decoder_task_runner,
      base::WeakPtr<VideoDecoderMixin::Client> client);
  ~VaapiVideoDecoder() override;

  // Schedule the next decode task in the queue to be executed.
  void ScheduleNextDecodeTask();
  // Try to decode a single input buffer.
  void HandleDecodeTask();
  // Clear the decode task queue. This is done when resetting or destroying the
  // decoder, or encountering an error.
  void ClearDecodeTaskQueue(DecodeStatus status);

  // Releases the local reference to the VideoFrame associated with the
  // specified |surface_id| on the decoder thread. This is called when
  // |decoder_| has outputted the VideoFrame and stopped using it as a
  // reference frame. Note that this doesn't mean the frame can be reused
  // immediately, as it might still be used by the client.
  void ReleaseVideoFrame(VASurfaceID surface_id);
  // Callback for the frame pool to notify us when a frame becomes available.
  void NotifyFrameAvailable();
  // Callback from accelerator to indicate the protected state has been updated
  // so we can proceed or fail.
  void ProtectedSessionUpdate(bool success);

  // Flushes |decoder_|, blocking until all pending decode tasks have been
  // executed and all frames have been output.
  void Flush();

  // Called when resetting the decoder is finished, to execute |reset_cb|.
  void ResetDone(base::OnceClosure reset_cb);

  // Create codec-specific AcceleratedVideoDecoder and reset related variables.
  Status CreateAcceleratedVideoDecoder();

  // Change the current |state_| to the specified |state|.
  void SetState(State state);

  // Tell SetState() to change the |state_| to kError and send |message| to
  // MediaLog and to LOG(ERROR).
  void SetErrorState(std::string message);

  // Callback for the CDM to notify |this|.
  void OnCdmContextEvent(CdmContext::Event event);

  // This is a callback from ApplyResolutionChange() when we need to query the
  // browser process for the screen sizes.
  void ApplyResolutionChangeWithScreenSizes(
      const std::vector<gfx::Size>& screen_resolution);

  // Having too many decoder instances at once may cause us to run out of FDs
  // and subsequently crash (b/181264362). To avoid that, we limit the maximum
  // number of decoder instances that can exist at once. |num_instances_| tracks
  // that number.
  //
  // TODO(andrescj): we can relax this once we extract video decoding into its
  // own process.
  static constexpr int kMaxNumOfInstances = 16;
  static base::AtomicRefCount num_instances_;

  // The video decoder's state.
  State state_ = State::kUninitialized;

  // Callback used to notify the client when a frame is available for output.
  OutputCB output_cb_;

  // Callback used to notify the client when we have lost decode context and
  // request a reset (Used in protected decoding).
  WaitingCB waiting_cb_;

  // Bitstream information, written during Initialize().
  VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
  VideoColorSpace color_space_;
  absl::optional<gfx::HDRMetadata> hdr_metadata_;

  // Aspect ratio from the config.
  VideoAspectRatio aspect_ratio_;

  // 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::MRUCache<int32_t, base::TimeDelta> buffer_id_to_timestamp_;

  // Queue containing all requested decode tasks.
  base::queue<DecodeTask> decode_task_queue_;
  // The decode task we're currently trying to execute.
  absl::optional<DecodeTask> current_decode_task_;
  // The next input buffer id.
  int32_t next_buffer_id_ = 0;

  // The list of frames currently used as output buffers or reference frames.
  std::map<VASurfaceID, scoped_refptr<VideoFrame>> output_frames_;

  // VASurfaces are created via importing resources from a DmabufVideoFramePool
  // into libva in CreateSurface(). The following map keeps those VASurfaces for
  // reuse according to the expectations of libva vaDestroySurfaces(): "Surfaces
  // can only be destroyed after all contexts using these surfaces have been
  // destroyed."
  // TODO(crbug.com/1040291): remove this keep-alive when using SharedImages.
  base::small_map<std::map<gfx::GpuMemoryBufferId, scoped_refptr<VASurface>>>
      allocated_va_surfaces_;

  // We need to use a CdmContextRef so that we destruct
  // |cdm_event_cb_registration_| before the CDM is destructed. The CDM has
  // mechanisms to ensure destruction on the proper thread.
  //
  // For clarity, the MojoVideoDecoderService does hold a reference to both the
  // decoder and the CDM to ensure the CDM doesn't get destructed before the
  // decoder; however, in the VideoDecoderPipeline, which owns the
  // VaapiVideoDecoder, it uses an asynchronous destructor to destroy the
  // pipeline (and thus the VaapiVideoDecoder) on the decoder thread.
  std::unique_ptr<CdmContextRef> cdm_context_ref_;

  EncryptionScheme encryption_scheme_;

#if BUILDFLAG(IS_CHROMEOS_ASH)
  // To keep the CdmContext event callback registered.
  std::unique_ptr<CallbackRegistration> cdm_event_cb_registration_;
#endif

  // Platform and codec specific video decoder.
  std::unique_ptr<AcceleratedVideoDecoder> decoder_;
  scoped_refptr<VaapiWrapper> vaapi_wrapper_;
  // TODO(crbug.com/1022246): Instead of having the raw pointer here, getting
  // the pointer from AcceleratedVideoDecoder.
  VaapiVideoDecoderDelegate* decoder_delegate_ = nullptr;

  // This is used on AMD protected content implementations to indicate that the
  // DecoderBuffers we receive have been transcrypted and need special handling.
  bool transcryption_ = false;

  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtr<VaapiVideoDecoder> weak_this_;
  base::WeakPtrFactory<VaapiVideoDecoder> weak_this_factory_;

  DISALLOW_COPY_AND_ASSIGN(VaapiVideoDecoder);
};

}  // namespace media

#endif  // MEDIA_GPU_VAAPI_VAAPI_VIDEO_DECODER_H_