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

media / gpu / chromeos / decoder_buffer_transcryptor.h [blame]

// Copyright 2021 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_CHROMEOS_DECODER_BUFFER_TRANSCRYPTOR_H_
#define MEDIA_GPU_CHROMEOS_DECODER_BUFFER_TRANSCRYPTOR_H_

#include <memory>
#include <optional>

#include "base/containers/circular_deque.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "media/base/callback_registry.h"
#include "media/base/cdm_context.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decoder_status.h"
#include "media/base/decryptor.h"
#include "media/base/video_decoder.h"

namespace media {

class VideoDecoderMixin;

// This is used to send buffers to the CdmContext's Decryptor prior to sending
// them into the decoder for VideoDecoderPipeline. This is used in AMD
// implementations for protected content where the Decryptor normalizes the
// decryption before being passed into the HW decoders.
class DecoderBufferTranscryptor {
 public:
  using OnBufferTranscryptedCB =
      base::RepeatingCallback<void(scoped_refptr<DecoderBuffer>,
                                   VideoDecoder::DecodeCB)>;

  // The |transcrypt_callback| is invoked upon transcryption of a buffer. It
  // will be called with a nullptr in the event of failure.
  DecoderBufferTranscryptor(CdmContext* cdm_context,
                            VideoDecoderMixin& decoder,
                            bool needs_vp9_superframe_splitting,
                            OnBufferTranscryptedCB transcrypt_callback,
                            WaitingCB waiting_callback);
  DecoderBufferTranscryptor(const DecoderBufferTranscryptor&) = delete;
  DecoderBufferTranscryptor& operator=(const DecoderBufferTranscryptor&) =
      delete;
  ~DecoderBufferTranscryptor();

  // Enqueues a DecoderBuffer for transcryption. When complete, the callback
  // passed into the constructor will be invoked.
  void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer,
                     VideoDecoder::DecodeCB decode_cb);

  // Removes all pending tasks and invokes all pending VideoDecoder::DecodeCB
  // callbacks with the passed in |status|.
  void Reset(DecoderStatus status);

  // Invoked when more secure buffers might be available. When we have pending
  // tasks that are stalled due to secure buffer exhaustion, this is the
  // mechanism by which we will retry them.
  void SecureBuffersMayBeAvailable();

 private:
  // Transcrypt task holding single transcrypt request.
  struct TranscryptTask {
    TranscryptTask(scoped_refptr<DecoderBuffer> buffer,
                   VideoDecoder::DecodeCB decode_done_cb);
    TranscryptTask(const TranscryptTask&) = delete;
    TranscryptTask& operator=(const TranscryptTask&) = delete;
    ~TranscryptTask();
    TranscryptTask(TranscryptTask&&);
    TranscryptTask& operator=(TranscryptTask&&) = default;
    scoped_refptr<DecoderBuffer> buffer;
    VideoDecoder::DecodeCB decode_done_cb;
  };

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

  // Called to decrypt (i.e. transcrypt in our case) any pending buffers
  // available in the queue.
  void DecryptPendingBuffer();

  // Callback for the Decrypt call on transcryption.
  void OnBufferTranscrypted(Decryptor::Status status,
                            scoped_refptr<DecoderBuffer> transcrypted_buffer);

  void OnSecureBufferRelease(uint64_t secure_handle,
                             VideoDecoder::DecodeCB decode_cb,
                             DecoderStatus status);

  const raw_ref<VideoDecoderMixin> decoder_;  // Not owned.
  OnBufferTranscryptedCB transcrypt_callback_;
  WaitingCB waiting_callback_;

  // Indicates if a new usable key has become available while waiting for a
  // transcryption to complete. This allows us to detect if we need to retry
  // the transcryption if it fails due to the absence of a usable key.
  bool key_added_while_decrypting_ = false;

  // Queue containing all requested transcrypt tasks.
  base::circular_deque<TranscryptTask> transcrypt_task_queue_;
  // The transcrypt task we're currently trying to execute.
  std::optional<TranscryptTask> current_transcrypt_task_;

  // If true, then a request to the decryptor is in progress which means we
  // should not make another transcryption request until the pending one
  // completes (through a call to OnBufferTranscrypted()).
  // NOTE: The Decryptor implementation in use does support multiple
  // simultaneous calls to Decrypt, however we still throttle ourselves so we
  // don't end up with a backlog of Decrypt requests that need to be processed
  // before moving on after a Reset.
  bool transcrypt_pending_ = false;

  // If true, then we should split VP9 superframes up into individual frames
  // before decryption/decode.
  const bool needs_vp9_superframe_splitting_;

  // 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.
  std::unique_ptr<CdmContextRef> cdm_context_ref_;

  // To keep the CdmContext event callback registered.
  std::unique_ptr<CallbackRegistration> cdm_event_cb_registration_;

  SEQUENCE_CHECKER(sequence_checker_);

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

}  // namespace media
#endif  // MEDIA_GPU_CHROMEOS_DECODER_BUFFER_TRANSCRYPTOR_H_