blob: f5c157b3cdb0dd2e6dc157cb7717f0a3ac9e8906 [file] [log] [blame]
// Copyright 2021 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.
#include <memory>
#include "base/callback_forward.h"
#include "base/containers/queue.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"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace media {
// 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 {
using OnBufferTranscryptedCB =
// 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,
OnBufferTranscryptedCB transcrypt_callback,
WaitingCB waiting_callback);
DecoderBufferTranscryptor(const DecoderBufferTranscryptor&) = delete;
DecoderBufferTranscryptor& operator=(const 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);
// 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& 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);
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::queue<TranscryptTask> transcrypt_task_queue_;
// The transcrypt task we're currently trying to execute.
absl::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;
// 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_;
base::WeakPtr<DecoderBufferTranscryptor> weak_this_;
base::WeakPtrFactory<DecoderBufferTranscryptor> weak_this_factory_{this};
} // namespace media