summaryrefslogtreecommitdiffstats
path: root/content/common/gpu/media/android_video_decode_accelerator.h
blob: 3f20037b7dd2a902cf909779d9043f2ec6bb187f (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
// Copyright (c) 2013 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 CONTENT_COMMON_GPU_MEDIA_ANDROID_VIDEO_DECODE_ACCELERATOR_H_
#define CONTENT_COMMON_GPU_MEDIA_ANDROID_VIDEO_DECODE_ACCELERATOR_H_

#include <stdint.h>

#include <list>
#include <map>
#include <queue>
#include <string>
#include <vector>

#include "base/compiler_specific.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "content/common/content_export.h"
#include "content/common/gpu/media/avda_state_provider.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "media/base/android/media_drm_bridge.h"
#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/media_keys.h"
#include "media/video/video_decode_accelerator.h"

namespace gfx {
class SurfaceTexture;
}

namespace content {

// A VideoDecodeAccelerator implementation for Android.
// This class decodes the input encoded stream by using Android's MediaCodec
// class. http://developer.android.com/reference/android/media/MediaCodec.html
// It delegates attaching pictures to PictureBuffers to a BackingStrategy, but
// otherwise handles the work of transferring data to / from MediaCodec.
class CONTENT_EXPORT AndroidVideoDecodeAccelerator
    : public media::VideoDecodeAccelerator,
      public AVDAStateProvider {
 public:
  typedef std::map<int32_t, media::PictureBuffer> OutputBufferMap;

  // A BackingStrategy is responsible for making a PictureBuffer's texture
  // contain the image that a MediaCodec decoder buffer tells it to.
  class BackingStrategy {
   public:
    virtual ~BackingStrategy() {}

    // Called after the state provider is given, but before any other
    // calls to the BackingStrategy.
    virtual void Initialize(AVDAStateProvider* provider) = 0;

    // Called before the AVDA does any Destroy() work.  This will be
    // the last call that the BackingStrategy receives.
    virtual void Cleanup(bool have_context,
                         const OutputBufferMap& buffer_map) = 0;

    // Return the GL texture target that the PictureBuffer textures use.
    virtual uint32_t GetTextureTarget() const = 0;

    // Create and return a surface texture for the MediaCodec to use.
    virtual scoped_refptr<gfx::SurfaceTexture> CreateSurfaceTexture() = 0;

    // Make the provided PictureBuffer draw the image that is represented by
    // the decoded output buffer at codec_buffer_index.
    virtual void UseCodecBufferForPictureBuffer(
        int32_t codec_buffer_index,
        const media::PictureBuffer& picture_buffer) = 0;

    // Notify strategy that a picture buffer has been assigned.
    virtual void AssignOnePictureBuffer(
        const media::PictureBuffer& picture_buffer) {}

    // Notify strategy that a picture buffer has been reused.
    virtual void ReuseOnePictureBuffer(
        const media::PictureBuffer& picture_buffer) {}

    // Notify strategy that we are about to dismiss a picture buffer.
    virtual void DismissOnePictureBuffer(
        const media::PictureBuffer& picture_buffer) {}

    // Notify strategy that we have a new android MediaCodec instance.  This
    // happens when we're starting up or re-configuring mid-stream.  Any
    // previously provided codec should no longer be referenced.
    // For convenience, a container of PictureBuffers is provided in case
    // per-image cleanup is needed.
    virtual void CodecChanged(media::VideoCodecBridge* codec,
                              const OutputBufferMap& buffer_map) = 0;

    // Notify the strategy that a frame is available.  This callback can happen
    // on any thread at any time.
    virtual void OnFrameAvailable() = 0;
  };

  AndroidVideoDecodeAccelerator(
      const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder,
      const base::Callback<bool(void)>& make_context_current);

  ~AndroidVideoDecodeAccelerator() override;

  // media::VideoDecodeAccelerator implementation:
  bool Initialize(const Config& config, Client* client) override;
  void SetCdm(int cdm_id) override;
  void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
  void AssignPictureBuffers(
      const std::vector<media::PictureBuffer>& buffers) override;
  void ReusePictureBuffer(int32_t picture_buffer_id) override;
  void Flush() override;
  void Reset() override;
  void Destroy() override;
  bool CanDecodeOnIOThread() override;

  // AVDAStateProvider implementation:
  const gfx::Size& GetSize() const override;
  const base::ThreadChecker& ThreadChecker() const override;
  base::WeakPtr<gpu::gles2::GLES2Decoder> GetGlDecoder() const override;
  void PostError(const ::tracked_objects::Location& from_here,
                 media::VideoDecodeAccelerator::Error error) override;

  static media::VideoDecodeAccelerator::Capabilities GetCapabilities();

  // Notifies about SurfaceTexture::OnFrameAvailable.  This can happen on any
  // thread at any time!
  void OnFrameAvailable();

 private:
  // TODO(timav): evaluate the need for more states in the AVDA state machine.
  enum State {
    NO_ERROR,
    ERROR,
    WAITING_FOR_KEY,
  };

  static const base::TimeDelta kDecodePollDelay;

  // Configures |media_codec_| with the given codec parameters from the client.
  bool ConfigureMediaCodec();

  // Sends the decoded frame specified by |codec_buffer_index| to the client.
  void SendDecodedFrameToClient(int32_t codec_buffer_index,
                                int32_t bitstream_id);

  // Does pending IO tasks if any. Once this is called, it polls |media_codec_|
  // until it finishes pending tasks. For the polling, |kDecodePollDelay| is
  // used.
  void DoIOTask();

  // Feeds input data to |media_codec_|. This checks
  // |pending_bitstream_buffers_| and queues a buffer to |media_codec_|.
  // Returns true if any input was processed.
  bool QueueInput();

  // Dequeues output from |media_codec_| and feeds the decoded frame to the
  // client.  Returns a hint about whether calling again might produce
  // more output.
  bool DequeueOutput();

  // Requests picture buffers from the client.
  void RequestPictureBuffers();

  // This callback is called after CDM obtained a MediaCrypto object.
  void OnMediaCryptoReady(media::MediaDrmBridge::JavaObjectPtr media_crypto,
                          bool needs_protected_surface);

  // This callback is called when a new key is added to CDM.
  void OnKeyAdded();

  // Notifies the client of the CDM setting result.
  void NotifyCdmAttached(bool success);

  // Notifies the client about the availability of a picture.
  void NotifyPictureReady(const media::Picture& picture);

  // Notifies the client that the input buffer identifed by input_buffer_id has
  // been processed.
  void NotifyEndOfBitstreamBuffer(int input_buffer_id);

  // Notifies the client that the decoder was flushed.
  void NotifyFlushDone();

  // Notifies the client that the decoder was reset.
  void NotifyResetDone();

  // Notifies about decoding errors.
  void NotifyError(media::VideoDecodeAccelerator::Error error);

  // Start or stop our work-polling timer based on whether we did any work, and
  // how long it has been since we've done work.  Calling this with true will
  // start the timer.  Calling it with false may stop the timer.
  void ManageTimer(bool did_work);

  // Resets MediaCodec and buffers/containers used for storing output. These
  // components need to be reset upon EOS to decode a later stream. Input state
  // (e.g. queued BitstreamBuffers) is not reset, as input following an EOS
  // is still valid and should be processed.
  void ResetCodecState();

  // Dismiss all |output_picture_buffers_| in preparation for requesting new
  // ones.
  void DismissPictureBuffers();

  // Return true if and only if we should use deferred rendering.
  static bool UseDeferredRenderingStrategy();

  // Used to DCHECK that we are called on the correct thread.
  base::ThreadChecker thread_checker_;

  // To expose client callbacks from VideoDecodeAccelerator.
  Client* client_;

  // Callback to set the correct gl context.
  base::Callback<bool(void)> make_context_current_;

  // Codec type. Used when we configure media codec.
  media::VideoCodec codec_;

  // Whether the stream is encrypted.
  bool is_encrypted_;

  // Whether encryption scheme requires to use protected surface.
  bool needs_protected_surface_;

  // The current state of this class. For now, this is used only for setting
  // error state.
  State state_;

  // This map maintains the picture buffers passed to the client for decoding.
  // The key is the picture buffer id.
  OutputBufferMap output_picture_buffers_;

  // This keeps the free picture buffer ids which can be used for sending
  // decoded frames to the client.
  std::queue<int32_t> free_picture_ids_;

  // Picture buffer ids which have been dismissed and not yet re-assigned.  Used
  // to ignore ReusePictureBuffer calls that were in flight when the
  // DismissPictureBuffer call was made.
  std::set<int32_t> dismissed_picture_ids_;

  // The low-level decoder which Android SDK provides.
  scoped_ptr<media::VideoCodecBridge> media_codec_;

  // A container of texture. Used to set a texture to |media_codec_|.
  scoped_refptr<gfx::SurfaceTexture> surface_texture_;

  // Set to true after requesting picture buffers to the client.
  bool picturebuffers_requested_;

  // The resolution of the stream.
  gfx::Size size_;

  // Encoded bitstream buffers to be passed to media codec, queued until an
  // input buffer is available, along with the time when they were first
  // enqueued.
  typedef std::queue<std::pair<media::BitstreamBuffer, base::Time> >
      PendingBitstreamBuffers;
  PendingBitstreamBuffers pending_bitstream_buffers_;

  // A map of presentation timestamp to bitstream buffer id for the bitstream
  // buffers that have been submitted to the decoder but haven't yet produced an
  // output frame with the same timestamp. Note: there will only be one entry
  // for multiple bitstream buffers that have the same presentation timestamp.
  std::map<base::TimeDelta, int32_t> bitstream_buffers_in_decoder_;

  // Keeps track of bitstream ids notified to the client with
  // NotifyEndOfBitstreamBuffer() before getting output from the bitstream.
  std::list<int32_t> bitstreams_notified_in_advance_;

  // Owner of the GL context. Used to restore the context state.
  base::WeakPtr<gpu::gles2::GLES2Decoder> gl_decoder_;

  // Repeating timer responsible for draining pending IO to the codec.
  base::RepeatingTimer io_timer_;

  // Backing strategy that we'll use to connect PictureBuffers to frames.
  scoped_ptr<BackingStrategy> strategy_;

  // Helper class that manages asynchronous OnFrameAvailable callbacks.
  class OnFrameAvailableHandler;
  scoped_refptr<OnFrameAvailableHandler> on_frame_available_handler_;

  // Time at which we last did useful work on io_timer_.
  base::TimeTicks most_recent_work_;

  // CDM related stuff.

  // Holds a ref-count to the CDM.
  scoped_refptr<media::MediaKeys> cdm_;

  // MediaDrmBridge requires registration/unregistration of the player, this
  // registration id is used for this.
  int cdm_registration_id_;

  // The MediaCrypto object is used in the MediaCodec.configure() in case of
  // an encrypted stream.
  media::MediaDrmBridge::JavaObjectPtr media_crypto_;

  // Index of the dequeued and filled buffer that we keep trying to enqueue.
  // Such buffer appears in MEDIA_CODEC_NO_KEY processing.
  int pending_input_buf_index_;

  // WeakPtrFactory for posting tasks back to |this|.
  base::WeakPtrFactory<AndroidVideoDecodeAccelerator> weak_this_factory_;

  friend class AndroidVideoDecodeAcceleratorTest;
};

}  // namespace content

#endif  // CONTENT_COMMON_GPU_MEDIA_ANDROID_VIDEO_DECODE_ACCELERATOR_H_