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
media / gpu / vaapi / vaapi_video_decoder_delegate.h [blame]
// Copyright 2019 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_VAAPI_VAAPI_VIDEO_DECODER_DELEGATE_H_
#define MEDIA_GPU_VAAPI_VAAPI_VIDEO_DECODER_DELEGATE_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "build/chromeos_buildflags.h"
#include "media/base/decryptor.h"
#include "media/base/encryption_scheme.h"
#include "media/base/subsample_entry.h"
#include "third_party/libva_protected_content/va_protected_content.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
namespace chromeos {
class ChromeOsCdmContext;
} // namespace chromeos
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace media {
class CdmContext;
class VaapiDecodeSurfaceHandler;
class DecryptConfig;
class VaapiWrapper;
class VASurface;
// The common part of each AcceleratedVideoDecoder's Accelerator for VA-API.
// This class allows clients to reset VaapiWrapper in case of a profile change.
// VaapiDecodeSurfaceHandler must stay alive for the lifetime of this class.
// This also handles all of the shared functionality relating to protected
// sessions in VA-API.
class VaapiVideoDecoderDelegate {
public:
// Callback when using protected mode to indicate that if waiting, the
// decoder should resume again. If |success| is false, then decoding should
// fail.
using ProtectedSessionUpdateCB = base::RepeatingCallback<void(bool success)>;
VaapiVideoDecoderDelegate(
VaapiDecodeSurfaceHandler* const vaapi_dec,
scoped_refptr<VaapiWrapper> vaapi_wrapper,
ProtectedSessionUpdateCB on_protected_session_update_cb,
CdmContext* cdm_context,
EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted);
virtual ~VaapiVideoDecoderDelegate();
void set_vaapi_wrapper(scoped_refptr<VaapiWrapper> vaapi_wrapper);
virtual void OnVAContextDestructionSoon();
VaapiVideoDecoderDelegate(const VaapiVideoDecoderDelegate&) = delete;
VaapiVideoDecoderDelegate& operator=(const VaapiVideoDecoderDelegate&) =
delete;
// Should be called when kTryAgain is returned from decoding to determine if
// we should try to recover the session by sending a kDecodeStateLost message
// up through the WaitingCB in the decoder. Returns true if we should send the
// kDecodeStateLost message.
bool HasInitiatedProtectedRecovery();
protected:
// Sets the |decrypt_config| currently active for this stream. Returns true if
// that config is compatible with the existing one (for example, you can't
// change encryption schemes midstream).
bool SetDecryptConfig(std::unique_ptr<DecryptConfig> decrypt_config);
enum class ProtectedSessionState {
kNotCreated,
kInProcess,
kCreated,
kNeedsRecovery,
kFailed
};
// Ensures we have a protected session setup and attached to the active
// |vaapi_wrapper_| we are using. We are in the corresponding state returned
// when this call returns. |full_sample| indicates if we are using full sample
// encryption or not and must remain consistent for a session. If everything
// is setup for a protected session, it will fill in the |crypto_params|.
// |segments| must retain its memory until the frame is submitted.
// |subsamples| is for the current slice. |size| is the size of the slice
// data. This should be called if IsEncrypted() is true even if the current
// data is not encrypted (i.e. |subsamples| is empty).
#if BUILDFLAG(IS_CHROMEOS_ASH)
ProtectedSessionState SetupDecryptDecode(
bool full_sample,
size_t size,
VAEncryptionParameters* crypto_params,
std::vector<VAEncryptionSegmentInfo>* segments,
const std::vector<SubsampleEntry>& subsamples);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Returns true if we are handling encrypted content, in which case
// SetupDecryptDecode() should be called for every slice. This is specifically
// for Intel platforms.
bool IsEncryptedSession() const {
return (encryption_scheme_ != EncryptionScheme::kUnencrypted) &&
!transcryption_;
}
// Returns true if we are handling transcrypted content. This is specifically
// for AMD platforms that normalize encrypted content with the TEE rather than
// passing all the parameters into libva.
bool IsTranscrypted() const { return transcryption_; }
// Should be called by subclasses if a failure occurs during actual decoding.
// This will check if we are using protected mode and it's in a state that
// can be recovered which should resolve the error. If this method returns
// true, then the caller should return kTryAgain from the accelerator to kick
// off the rest of the recovery process.
bool NeedsProtectedSessionRecovery();
// Should be invoked by subclasses if they successfully decoded protected
// video. This is so we can reset our tracker to indicate we successfully
// recovered from protected session loss. It is fine to call this method on
// every successful protected decode.
void ProtectedDecodedSucceeded();
// Returns the key_id string for the current DecryptConfig.
std::string GetDecryptKeyId() const;
// Both owned by caller.
const raw_ptr<VaapiDecodeSurfaceHandler> vaapi_dec_;
scoped_refptr<VaapiWrapper> vaapi_wrapper_;
SEQUENCE_CHECKER(sequence_checker_);
private:
void OnGetHwConfigData(bool success, const std::vector<uint8_t>& config_data);
void OnGetHwKeyData(const std::string& key_id,
Decryptor::Status status,
const std::vector<uint8_t>& key_data);
void RecoverProtectedSession();
// All members below pertain to protected content playback.
ProtectedSessionUpdateCB on_protected_session_update_cb_;
EncryptionScheme encryption_scheme_;
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Not owned.
raw_ptr<chromeos::ChromeOsCdmContext> chromeos_cdm_context_ = nullptr;
EncryptionScheme last_used_encryption_scheme_{EncryptionScheme::kUnencrypted};
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
ProtectedSessionState protected_session_state_;
std::unique_ptr<DecryptConfig> decrypt_config_;
std::vector<uint8_t> hw_identifier_;
std::map<std::string, std::vector<uint8_t>> hw_key_data_map_;
// This will only be true on AMD platforms where we support encrypted content
// and the content is encrypted.
bool transcryption_ = false;
// This gets set to true if we indicated we should try to recover from
// protected session loss. We use this so that we don't go into a loop where
// we repeatedly retry recovery over and over.
bool performing_recovery_;
base::WeakPtrFactory<VaapiVideoDecoderDelegate> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_GPU_VAAPI_VAAPI_VIDEO_DECODER_DELEGATE_H_