summaryrefslogtreecommitdiff
path: root/chromium/media/gpu/mac/vt_video_decode_accelerator_mac.h
blob: 5ec5bed52eb7bc43cb525af272e53d8f3af1d873 (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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// Copyright 2014 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_MAC_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_
#define MEDIA_GPU_MAC_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_

#include <stdint.h>

#include <map>
#include <memory>

#include "base/containers/queue.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "base/trace_event/memory_dump_provider.h"
#include "media/base/media_log.h"
#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
#include "media/gpu/media_gpu_export.h"
#include "media/video/h264_parser.h"
#include "media/video/h264_poc.h"
#include "media/video/video_decode_accelerator.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image_io_surface.h"

// This must be included after gl_bindings.h, or the various GL headers on the
// system and in the source tree will conflict with each other.
#include <VideoToolbox/VideoToolbox.h>

namespace media {
class VP9ConfigChangeDetector;
class VP9SuperFrameBitstreamFilter;

// Preload VideoToolbox libraries, needed for sandbox warmup.
MEDIA_GPU_EXPORT bool InitializeVideoToolbox();

// VideoToolbox.framework implementation of the VideoDecodeAccelerator
// interface for Mac OS X (currently limited to 10.9+).
class VTVideoDecodeAccelerator : public VideoDecodeAccelerator,
                                 public base::trace_event::MemoryDumpProvider {
 public:
  VTVideoDecodeAccelerator(const GpuVideoDecodeGLClient& gl_client_,
                           MediaLog* media_log);

  ~VTVideoDecodeAccelerator() override;

  // VideoDecodeAccelerator implementation.
  bool Initialize(const Config& config, Client* client) override;
  void Decode(BitstreamBuffer bitstream) override;
  void Decode(scoped_refptr<DecoderBuffer> buffer,
              int32_t bitstream_id) override;
  void AssignPictureBuffers(
      const std::vector<PictureBuffer>& pictures) override;
  void ReusePictureBuffer(int32_t picture_id) override;
  void Flush() override;
  void Reset() override;
  void Destroy() override;
  bool TryToSetupDecodeOnSeparateThread(
      const base::WeakPtr<Client>& decode_client,
      const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner)
      override;
  bool SupportsSharedImagePictureBuffers() const override;

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

  // Called by OutputThunk() when VideoToolbox finishes decoding a frame.
  void Output(void* source_frame_refcon,
              OSStatus status,
              CVImageBufferRef image_buffer);

  static VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles();

 private:
  // Logged to UMA, so never reuse values. Make sure to update
  // VTVDASessionFailureType in histograms.xml to match.
  enum VTVDASessionFailureType {
    SFT_SUCCESSFULLY_INITIALIZED = 0,
    SFT_PLATFORM_ERROR = 1,
    SFT_INVALID_STREAM = 2,
    SFT_UNSUPPORTED_STREAM_PARAMETERS = 3,
    SFT_DECODE_ERROR = 4,
    SFT_UNSUPPORTED_STREAM = 5,
    // Must always be equal to largest entry logged.
    SFT_MAX = SFT_UNSUPPORTED_STREAM
  };

  enum State {
    STATE_DECODING,
    STATE_ERROR,
    STATE_DESTROYING,
  };

  enum TaskType {
    TASK_FRAME,
    TASK_FLUSH,
    TASK_RESET,
    TASK_DESTROY,
  };

  struct Frame {
    explicit Frame(int32_t bitstream_id);
    ~Frame();

    // Associated bitstream buffer.
    int32_t bitstream_id;

    // Slice header information.
    bool has_slice = false;
    bool is_idr = false;
    bool has_mmco5 = false;
    int32_t pic_order_cnt = 0;
    int32_t reorder_window = 0;

    // Clean aperture size, as computed by CoreMedia.
    gfx::Size image_size;

    // Decoded image, if decoding was successful.
    base::ScopedCFTypeRef<CVImageBufferRef> image;
  };

  struct Task {
    Task(TaskType type);
    Task(Task&& other);
    ~Task();

    TaskType type;
    std::unique_ptr<Frame> frame;
  };

  struct PictureInfo {
    // A PictureInfo that specifies no texture IDs will be used for shared
    // images.
    PictureInfo();
    PictureInfo(uint32_t client_texture_id, uint32_t service_texture_id);
    ~PictureInfo();

    // If true, then |scoped_shared_image| is used and |client_texture_id| and
    // |service_texture_id| are not used.
    const bool uses_shared_images;

    // Information about the currently bound image, for OnMemoryDump().
    scoped_refptr<gl::GLImageIOSurface> gl_image;
    int32_t bitstream_id = 0;

    // Texture IDs for the image buffer.
    const uint32_t client_texture_id = 0;
    const uint32_t service_texture_id = 0;

    // The shared image holder that will be passed to the client.
    scoped_refptr<Picture::ScopedSharedImage> scoped_shared_image;

   private:
    DISALLOW_COPY_AND_ASSIGN(PictureInfo);
  };

  struct FrameOrder {
    bool operator()(const std::unique_ptr<Frame>& lhs,
                    const std::unique_ptr<Frame>& rhs) const;
  };

  //
  // Methods for interacting with VideoToolbox. Run on |decoder_thread_|.
  //

  // Set up VideoToolbox using the current SPS and PPS. Returns true or calls
  // NotifyError() before returning false.
  bool ConfigureDecoder();

  // Wait for VideoToolbox to output all pending frames. Returns true or calls
  // NotifyError() before returning false.
  bool FinishDelayedFrames();

  // |frame| is owned by |pending_frames_|.
  void DecodeTask(scoped_refptr<DecoderBuffer> buffer, Frame* frame);
  void DecodeTaskVp9(scoped_refptr<DecoderBuffer> buffer, Frame* frame);
  void DecodeDone(Frame* frame);

  //
  // Methods for interacting with |client_|. Run on |gpu_task_runner_|.
  //
  void NotifyError(Error vda_error_type,
                   VTVDASessionFailureType session_failure_type);

  // Since |media_log_| is invalidated in Destroy() on the GPU thread, the easy
  // thing to do is post to the GPU thread to use it. This helper handles the
  // thread hop if necessary.
  void WriteToMediaLog(MediaLogMessageLevel level, const std::string& message);

  // |type| is the type of task that the flush will complete, one of TASK_FLUSH,
  // TASK_RESET, or TASK_DESTROY.
  void QueueFlush(TaskType type);
  void FlushTask(TaskType type);
  void FlushDone(TaskType type);

  // Try to make progress on tasks in the |task_queue_| or sending frames in the
  // |reorder_queue_|.
  void ProcessWorkQueues();

  // These methods returns true if a task was completed, false otherwise.
  bool ProcessTaskQueue();
  bool ProcessReorderQueue();
  bool ProcessOutputQueue();
  bool ProcessFrame(const Frame& frame);
  bool SendFrame(const Frame& frame);

  //
  // GPU thread state.
  //
  const GpuVideoDecodeGLClient gl_client_;
  MediaLog* media_log_;

  VideoDecodeAccelerator::Client* client_ = nullptr;
  State state_ = STATE_DECODING;

  // Queue of pending flush tasks. This is used to drop frames when a reset
  // is pending.
  base::queue<TaskType> pending_flush_tasks_;

  // Queue of tasks to complete in the GPU thread.
  base::queue<Task> task_queue_;

  // Queue of decoded frames in presentation order.
  std::priority_queue<std::unique_ptr<Frame>,
                      std::vector<std::unique_ptr<Frame>>,
                      FrameOrder>
      reorder_queue_;

  // Queue of decoded frames in presentation order. Used by codecs which don't
  // require reordering (VP9 only at the moment).
  std::deque<std::unique_ptr<Frame>> output_queue_;

  std::unique_ptr<VP9ConfigChangeDetector> cc_detector_;
  std::unique_ptr<VP9SuperFrameBitstreamFilter> vp9_bsf_;

  // Size of assigned picture buffers.
  gfx::Size picture_size_;

  // Frames that have not yet been decoded, keyed by bitstream ID; maintains
  // ownership of Frame objects while they flow through VideoToolbox.
  std::map<int32_t, std::unique_ptr<Frame>> pending_frames_;

  // Set of assigned bitstream IDs, so that Destroy() can release them all.
  std::set<int32_t> assigned_bitstream_ids_;

  // All picture buffers assigned to us. Used to check if reused picture buffers
  // should be added back to the available list or released. (They are not
  // released immediately because we need the reuse event to free the binding.)
  std::set<int32_t> assigned_picture_ids_;

  // Texture IDs and image buffers of assigned pictures.
  std::map<int32_t, std::unique_ptr<PictureInfo>> picture_info_map_;

  // Pictures ready to be rendered to.
  std::vector<int32_t> available_picture_ids_;

  //
  // Decoder thread state.
  //
  VTDecompressionOutputCallbackRecord callback_;
  base::ScopedCFTypeRef<CMFormatDescriptionRef> format_;
  base::ScopedCFTypeRef<VTDecompressionSessionRef> session_;
  H264Parser parser_;

  // SPSs and PPSs seen in the bitstream.
  std::map<int, std::vector<uint8_t>> seen_sps_;
  std::map<int, std::vector<uint8_t>> seen_spsext_;
  std::map<int, std::vector<uint8_t>> seen_pps_;

  // SPS and PPS most recently activated by an IDR.
  // TODO(sandersd): Enable configuring with multiple PPSs.
  std::vector<uint8_t> active_sps_;
  std::vector<uint8_t> active_spsext_;
  std::vector<uint8_t> active_pps_;

  // SPS and PPS the decoder is currently confgured with.
  std::vector<uint8_t> configured_sps_;
  std::vector<uint8_t> configured_spsext_;
  std::vector<uint8_t> configured_pps_;

  Config config_;
  VideoCodec codec_;

  // Visible rect the decoder is configured to use.
  gfx::Size configured_size_;

  bool waiting_for_idr_ = true;
  bool missing_idr_logged_ = false;
  H264POC poc_;

  // Id number for this instance for memory dumps.
  int memory_dump_id_ = 0;

  //
  // Shared state (set up and torn down on GPU thread).
  //
  scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
  base::WeakPtr<VTVideoDecodeAccelerator> weak_this_;
  base::Thread decoder_thread_;

  // Declared last to ensure that all weak pointers are invalidated before
  // other destructors run.
  base::WeakPtrFactory<VTVideoDecodeAccelerator> weak_this_factory_;

  DISALLOW_COPY_AND_ASSIGN(VTVideoDecodeAccelerator);
};

}  // namespace media

#endif  // MEDIA_GPU_MAC_VT_VIDEO_DECODE_ACCELERATOR_MAC_H_