summaryrefslogtreecommitdiff
path: root/chromium/media/filters/gpu_video_decoder.h
blob: ef04bf9ad64f3a7d5ecaf21a43820f7e1f9128a2 (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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// Copyright (c) 2012 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_FILTERS_GPU_VIDEO_DECODER_H_
#define MEDIA_FILTERS_GPU_VIDEO_DECODER_H_

#include <stddef.h>
#include <stdint.h>

#include <list>
#include <map>
#include <set>
#include <utility>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/memory_dump_provider.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "media/base/overlay_info.h"
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder.h"
#include "media/video/video_decode_accelerator.h"

template <class T> class scoped_refptr;

namespace base {
class SharedMemory;
}

namespace gpu {
struct SyncToken;
}

namespace media {

class DecoderBuffer;
class GpuVideoAcceleratorFactories;
class MediaLog;

// GPU-accelerated video decoder implementation.  Relies on
// AcceleratedVideoDecoderMsg_Decode and friends.  Can be created on any thread
// but must be accessed and destroyed on GpuVideoAcceleratorFactories's
// GetMessageLoop().
class MEDIA_EXPORT GpuVideoDecoder
    : public VideoDecoder,
      public VideoDecodeAccelerator::Client,
      public base::trace_event::MemoryDumpProvider {
 public:
  GpuVideoDecoder(GpuVideoAcceleratorFactories* factories,
                  const RequestOverlayInfoCB& request_overlay_info_cb,
                  const gfx::ColorSpace& target_color_space,
                  MediaLog* media_log);
  ~GpuVideoDecoder() override;

  // VideoDecoder implementation.
  std::string GetDisplayName() const override;
  bool IsPlatformDecoder() const override;
  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 closure) override;
  bool NeedsBitstreamConversion() const override;
  bool CanReadWithoutStalling() const override;
  int GetMaxDecodeRequests() const override;

  // VideoDecodeAccelerator::Client implementation.
  void NotifyInitializationComplete(bool success) override;
  void ProvidePictureBuffers(uint32_t count,
                             VideoPixelFormat format,
                             uint32_t textures_per_buffer,
                             const gfx::Size& size,
                             uint32_t texture_target) override;
  void DismissPictureBuffer(int32_t id) override;
  void PictureReady(const media::Picture& picture) override;
  void NotifyEndOfBitstreamBuffer(int32_t id) override;
  void NotifyFlushDone() override;
  void NotifyResetDone() override;
  void NotifyError(media::VideoDecodeAccelerator::Error error) override;

  // base::trace_event::MemoryDumpProvider implementation.
  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                    base::trace_event::ProcessMemoryDump* pmd) override;

  static const char kDecoderName[];

 private:
  enum State {
    kNormal,
    kDrainingDecoder,
    kDecoderDrained,
    kError
  };

  // A SHMBuffer and the DecoderBuffer its data came from.
  struct PendingDecoderBuffer;

  typedef std::map<int32_t, PictureBuffer> PictureBufferMap;

  void DeliverFrame(scoped_refptr<VideoFrame> frame);

  // Static method is to allow it to run even after GVD is deleted.
  static void ReleaseMailbox(base::WeakPtr<GpuVideoDecoder> decoder,
                             media::GpuVideoAcceleratorFactories* factories,
                             int64_t picture_buffer_id,
                             PictureBuffer::TextureIds ids,
                             const gpu::SyncToken& release_sync_token);
  // Indicate the picture buffer can be reused by the decoder.
  void ReusePictureBuffer(int64_t picture_buffer_id);

  void RecordBufferData(
      const BitstreamBuffer& bitstream_buffer, const DecoderBuffer& buffer);
  void GetBufferData(int32_t id,
                     base::TimeDelta* timetamp,
                     gfx::Rect* visible_rect,
                     gfx::Size* natural_size);

  void DestroyVDA();

  // Request a shared-memory segment of at least |min_size| bytes.  Will
  // allocate as necessary. May return nullptr during Shutdown.
  std::unique_ptr<base::SharedMemory> GetSharedMemory(size_t min_size);

  // Return a shared-memory segment to the available pool.
  void PutSharedMemory(std::unique_ptr<base::SharedMemory> shm_buffer,
                       int32_t last_bitstream_buffer_id);

  // Destroy all the assigned picture buffers and delete their textures, but
  // skip the textures of the buffers which is still at display.
  void DestroyPictureBuffers();

  // Returns true if the video decoder with |capabilities| can support
  // |profile|, |coded_size|, and |is_encrypted|.
  bool IsProfileSupported(
      const VideoDecodeAccelerator::Capabilities& capabilities,
      VideoCodecProfile profile,
      const gfx::Size& coded_size,
      bool is_encrypted);

  // Assert the contract that this class is operated on the right thread.
  void DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() const;

  // Provided to the |request_overlay_info_cb_| callback given during
  // construction.  Sets or changes the output surface.
  void OnOverlayInfoAvailable(const OverlayInfo& overlay_info);

  // If the VDA supports external surfaces, we must wait for the surface before
  // completing initialization. This will be called by OnSurfaceAvailable() once
  // the surface is known or immediately by Initialize() if external surfaces
  // are unsupported.
  void CompleteInitialization(const OverlayInfo& overlay_info);

  // Return the number of picture buffers which ids are in
  // |assigned_picture_buffers_| but not in |picture_buffers_at_display_|.
  // It is used for checking and implementing CanReadWithoutStalling().
  size_t AvailablePictures() const;

  bool needs_bitstream_conversion_;

  GpuVideoAcceleratorFactories* factories_;

  // For requesting overlay info updates. If this is null, overlays are not
  // supported.
  RequestOverlayInfoCB request_overlay_info_cb_;
  bool overlay_info_requested_;

  gfx::ColorSpace target_color_space_;

  MediaLog* media_log_;

  // Populated during Initialize() (on success) and unchanged until an error
  // occurs.
  std::unique_ptr<VideoDecodeAccelerator> vda_;

  // Whether |vda_->Initialize()| has been called. This is used to avoid
  // calling Initialize() again while a deferred initialization is in progress.
  bool vda_initialized_;

  InitCB init_cb_;
  OutputCB output_cb_;

  DecodeCB eos_decode_cb_;

  // Not null only during reset.
  base::OnceClosure pending_reset_cb_;

  State state_;

  VideoDecoderConfig config_;

  // Shared-memory buffer pool.  Since allocating SHM segments requires a round-
  // trip to the browser process, we try to keep allocation out of the steady-
  // state of the decoder.
  //
  // The second value in the ShMemEntry is the last bitstream buffer id assigned
  // to that segment; it's used to erase segments which are no longer active.
  using ShMemEntry = std::pair<std::unique_ptr<base::SharedMemory>, int32_t>;
  class ShMemEntrySortedBySize {
   public:
    bool operator()(const ShMemEntry& lhs, const ShMemEntry& rhs) const {
      return lhs.first->mapped_size() < rhs.first->mapped_size();
    }
  };
  base::flat_set<ShMemEntry, ShMemEntrySortedBySize> available_shm_segments_;

  // Placeholder sync token that was created and validated after the most
  // recent picture buffers were created.
  gpu::SyncToken sync_token_;

  std::map<int32_t, PendingDecoderBuffer> bitstream_buffers_in_decoder_;
  PictureBufferMap assigned_picture_buffers_;
  // PictureBuffers given to us by VDA via PictureReady, which we sent forward
  // as VideoFrames to be rendered via decode_cb_, and which will be returned
  // to us via ReusePictureBuffer. Note that a picture buffer might be sent from
  // VDA multiple times. Therefore we use multimap to track the number of times
  // we passed the picture buffer for display.
  std::multimap<int32_t /* picture_buffer_id */,
                PictureBuffer::TextureIds /* texture_id */>
      picture_buffers_at_display_;

  struct BufferData {
    BufferData(int32_t bbid,
               base::TimeDelta ts,
               const gfx::Rect& visible_rect,
               const gfx::Size& natural_size);
    ~BufferData();
    int32_t bitstream_buffer_id;
    base::TimeDelta timestamp;
    gfx::Rect visible_rect;
    gfx::Size natural_size;
  };
  std::list<BufferData> input_buffer_data_;

  // picture_buffer_id and the frame wrapping the corresponding Picture, for
  // frames that have been decoded but haven't been requested by a Decode() yet.
  int32_t next_picture_buffer_id_;
  int32_t next_bitstream_buffer_id_;

  // If true, the client cannot expect the VDA to produce any new decoded
  // frames, until it returns all PictureBuffers it may be holding back to the
  // VDA. In other words, the VDA may require all PictureBuffers to be able to
  // proceed with decoding the next frame.
  bool needs_all_picture_buffers_to_decode_;

  // If true, then the VDA supports deferred initialization via
  // NotifyInitializationComplete.  Otherwise, it will return initialization
  // status synchronously from VDA::Initialize.
  bool supports_deferred_initialization_;

  // This flag translates to COPY_REQUIRED flag for each frame.
  bool requires_texture_copy_;

  // Set during Initialize(); given to the VDA for purposes for handling
  // encrypted content.
  int cdm_id_;

  // Minimum size for shared memory segments. Ideally chosen to optimize the
  // number of segments and total size of allocations over the course of a
  // playback.  See Initialize() for more details.
  size_t min_shared_memory_segment_size_;

  // |next_bitstream_buffer_id_| at the time we last performed a GC of no longer
  // used ShMemEntry objects in |available_shm_segments_|.  Updated whenever
  // PutSharedMemory() performs a GC.
  int32_t bitstream_buffer_id_of_last_gc_;

  // Bound to factories_->GetMessageLoop().
  // NOTE: Weak pointers must be invalidated before all other member variables.
  base::WeakPtrFactory<GpuVideoDecoder> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(GpuVideoDecoder);
};

}  // namespace media

#endif  // MEDIA_FILTERS_GPU_VIDEO_DECODER_H_