vaapi_video_decoder_delegate.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/gpu/vaapi/vaapi_video_decoder_delegate.h"
  5. #include "base/bind.h"
  6. #include "base/containers/contains.h"
  7. #include "base/logging.h"
  8. #include "base/numerics/safe_conversions.h"
  9. #include "base/time/default_tick_clock.h"
  10. #include "build/chromeos_buildflags.h"
  11. #include "media/base/bind_to_current_loop.h"
  12. #include "media/base/cdm_context.h"
  13. #include "media/gpu/decode_surface_handler.h"
  14. #include "media/gpu/vaapi/va_surface.h"
  15. #include "media/gpu/vaapi/vaapi_wrapper.h"
  16. #if BUILDFLAG(IS_CHROMEOS_ASH)
  17. // gn check does not account for BUILDFLAG(), so including these headers will
  18. // make gn check fail for builds other than ash-chrome. See gn help nogncheck
  19. // for more information.
  20. #include "chromeos/components/cdm_factory_daemon/chromeos_cdm_context.h" // nogncheck
  21. #include "chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h" // nogncheck
  22. namespace {
  23. // During playback of protected content, we need to request the keys at an
  24. // interval no greater than this. This allows updating of key usage data.
  25. constexpr base::TimeDelta kKeyRetrievalMaxPeriod = base::Minutes(1);
  26. // This increments the lower 64 bit counter of an 128 bit IV.
  27. void ctr128_inc64(uint8_t* counter) {
  28. uint32_t n = 16;
  29. do {
  30. if (++counter[--n] != 0)
  31. return;
  32. } while (n > 8);
  33. }
  34. } // namespace
  35. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  36. namespace media {
  37. VaapiVideoDecoderDelegate::VaapiVideoDecoderDelegate(
  38. DecodeSurfaceHandler<VASurface>* const vaapi_dec,
  39. scoped_refptr<VaapiWrapper> vaapi_wrapper,
  40. ProtectedSessionUpdateCB on_protected_session_update_cb,
  41. CdmContext* cdm_context,
  42. EncryptionScheme encryption_scheme)
  43. : vaapi_dec_(vaapi_dec),
  44. vaapi_wrapper_(std::move(vaapi_wrapper)),
  45. on_protected_session_update_cb_(
  46. std::move(on_protected_session_update_cb)),
  47. encryption_scheme_(encryption_scheme),
  48. protected_session_state_(ProtectedSessionState::kNotCreated),
  49. performing_recovery_(false) {
  50. DCHECK(vaapi_wrapper_);
  51. DCHECK(vaapi_dec_);
  52. DETACH_FROM_SEQUENCE(sequence_checker_);
  53. #if BUILDFLAG(IS_CHROMEOS_ASH)
  54. if (cdm_context)
  55. chromeos_cdm_context_ = cdm_context->GetChromeOsCdmContext();
  56. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  57. transcryption_ = cdm_context && VaapiWrapper::GetImplementationType() ==
  58. VAImplementation::kMesaGallium;
  59. }
  60. VaapiVideoDecoderDelegate::~VaapiVideoDecoderDelegate() {
  61. // TODO(mcasas): consider enabling the checker, https://crbug.com/789160
  62. // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  63. // Also destroy the protected session on destruction of the accelerator
  64. // delegate. That way if a new delegate is created, when it tries to create a
  65. // new protected session it won't overwrite the existing one.
  66. vaapi_wrapper_->DestroyProtectedSession();
  67. }
  68. void VaapiVideoDecoderDelegate::set_vaapi_wrapper(
  69. scoped_refptr<VaapiWrapper> vaapi_wrapper) {
  70. DETACH_FROM_SEQUENCE(sequence_checker_);
  71. vaapi_wrapper_ = std::move(vaapi_wrapper);
  72. protected_session_state_ = ProtectedSessionState::kNotCreated;
  73. hw_identifier_.clear();
  74. hw_key_data_map_.clear();
  75. }
  76. void VaapiVideoDecoderDelegate::OnVAContextDestructionSoon() {}
  77. bool VaapiVideoDecoderDelegate::HasInitiatedProtectedRecovery() {
  78. if (protected_session_state_ != ProtectedSessionState::kNeedsRecovery)
  79. return false;
  80. performing_recovery_ = true;
  81. protected_session_state_ = ProtectedSessionState::kNotCreated;
  82. return true;
  83. }
  84. bool VaapiVideoDecoderDelegate::SetDecryptConfig(
  85. std::unique_ptr<DecryptConfig> decrypt_config) {
  86. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  87. // It is possible to switch between clear and encrypted (and vice versa).
  88. if (!decrypt_config)
  89. return true;
  90. decrypt_config_ = std::move(decrypt_config);
  91. encryption_scheme_ = decrypt_config_->encryption_scheme();
  92. return true;
  93. }
  94. #if BUILDFLAG(IS_CHROMEOS_ASH)
  95. VaapiVideoDecoderDelegate::ProtectedSessionState
  96. VaapiVideoDecoderDelegate::SetupDecryptDecode(
  97. bool full_sample,
  98. size_t size,
  99. VAEncryptionParameters* crypto_params,
  100. std::vector<VAEncryptionSegmentInfo>* segments,
  101. const std::vector<SubsampleEntry>& subsamples) {
  102. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  103. DCHECK(crypto_params);
  104. DCHECK(segments);
  105. if (protected_session_state_ == ProtectedSessionState::kInProcess ||
  106. protected_session_state_ == ProtectedSessionState::kFailed) {
  107. return protected_session_state_;
  108. }
  109. if (protected_session_state_ == ProtectedSessionState::kNotCreated) {
  110. if (!chromeos_cdm_context_) {
  111. LOG(ERROR) << "Cannot create protected session w/out ChromeOsCdmContext";
  112. protected_session_state_ = ProtectedSessionState::kFailed;
  113. return protected_session_state_;
  114. }
  115. // We need to start the creation of this, first part requires getting the
  116. // hw config data from the daemon.
  117. chromeos_cdm_context_->GetHwConfigData(BindToCurrentLoop(
  118. base::BindOnce(&VaapiVideoDecoderDelegate::OnGetHwConfigData,
  119. weak_factory_.GetWeakPtr())));
  120. protected_session_state_ = ProtectedSessionState::kInProcess;
  121. return protected_session_state_;
  122. }
  123. DCHECK_EQ(protected_session_state_, ProtectedSessionState::kCreated);
  124. const bool ctr = (encryption_scheme_ == EncryptionScheme::kCenc);
  125. if (ctr) {
  126. crypto_params->encryption_type = full_sample
  127. ? VA_ENCRYPTION_TYPE_FULLSAMPLE_CTR
  128. : VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR;
  129. } else {
  130. crypto_params->encryption_type = full_sample
  131. ? VA_ENCRYPTION_TYPE_FULLSAMPLE_CBC
  132. : VA_ENCRYPTION_TYPE_SUBSAMPLE_CBC;
  133. }
  134. // For multi-slice we may already have segment information in here, so
  135. // calculate the current offset.
  136. size_t offset = 0;
  137. for (const auto& segment : *segments)
  138. offset += segment.segment_length;
  139. if (subsamples.empty() ||
  140. (subsamples.size() == 1 && subsamples[0].cypher_bytes == 0)) {
  141. // We still need to specify the crypto params to the driver for some reason
  142. // and indicate the entire content is clear.
  143. VAEncryptionSegmentInfo segment_info = {};
  144. segment_info.segment_start_offset = offset;
  145. segment_info.segment_length = segment_info.init_byte_length = size;
  146. if (decrypt_config_) {
  147. // We need to specify the IV even if the segment is clear.
  148. memcpy(segment_info.aes_cbc_iv_or_ctr, decrypt_config_->iv().data(),
  149. DecryptConfig::kDecryptionKeySize);
  150. }
  151. segments->emplace_back(std::move(segment_info));
  152. crypto_params->num_segments++;
  153. crypto_params->segment_info = &segments->front();
  154. return protected_session_state_;
  155. }
  156. // On Intel if we change encryption modes after we have started decrypting
  157. // then we need to rebuild the protected session.
  158. if (!IsTranscrypted() &&
  159. last_used_encryption_scheme_ != EncryptionScheme::kUnencrypted &&
  160. last_used_encryption_scheme_ != encryption_scheme_) {
  161. LOG(WARNING) << "Forcing rebuild since encryption mode changed midstream";
  162. RecoverProtectedSession();
  163. last_used_encryption_scheme_ = EncryptionScheme::kUnencrypted;
  164. return protected_session_state_;
  165. }
  166. last_used_encryption_scheme_ = encryption_scheme_;
  167. DCHECK(decrypt_config_);
  168. // We also need to make sure we have the key data for the active
  169. // DecryptConfig now that the protected session exists.
  170. if (!base::Contains(hw_key_data_map_, decrypt_config_->key_id())) {
  171. DVLOG(1) << "Looking up the key data for: " << decrypt_config_->key_id();
  172. chromeos_cdm_context_->GetHwKeyData(
  173. decrypt_config_.get(), hw_identifier_,
  174. BindToCurrentLoop(base::BindOnce(
  175. &VaapiVideoDecoderDelegate::OnGetHwKeyData,
  176. weak_factory_.GetWeakPtr(), decrypt_config_->key_id())));
  177. last_key_retrieval_time_ =
  178. base::DefaultTickClock::GetInstance()->NowTicks();
  179. // Don't change our state here because we are created, but we just return
  180. // kInProcess for now to trigger a wait/retry state.
  181. return ProtectedSessionState::kInProcess;
  182. }
  183. // We may also need to request the key in order to update key usage times in
  184. // OEMCrypto. We do care about the return value, because it will indicate key
  185. // validity for us.
  186. if (base::DefaultTickClock::GetInstance()->NowTicks() -
  187. last_key_retrieval_time_ >
  188. kKeyRetrievalMaxPeriod) {
  189. chromeos_cdm_context_->GetHwKeyData(
  190. decrypt_config_.get(), hw_identifier_,
  191. BindToCurrentLoop(base::BindOnce(
  192. &VaapiVideoDecoderDelegate::OnGetHwKeyData,
  193. weak_factory_.GetWeakPtr(), decrypt_config_->key_id())));
  194. last_key_retrieval_time_ =
  195. base::DefaultTickClock::GetInstance()->NowTicks();
  196. }
  197. crypto_params->num_segments += subsamples.size();
  198. // If the pattern has no skip blocks, which means the entire thing is
  199. // encrypted, then don't specify a pattern at all as Intel's implementation
  200. // does not expect that.
  201. if (decrypt_config_->HasPattern() &&
  202. decrypt_config_->encryption_pattern()->skip_byte_block()) {
  203. crypto_params->blocks_stripe_encrypted =
  204. decrypt_config_->encryption_pattern()->crypt_byte_block();
  205. crypto_params->blocks_stripe_clear =
  206. decrypt_config_->encryption_pattern()->skip_byte_block();
  207. }
  208. size_t total_cypher_size = 0;
  209. std::vector<uint8_t> iv(DecryptConfig::kDecryptionKeySize);
  210. iv.assign(decrypt_config_->iv().begin(), decrypt_config_->iv().end());
  211. for (const auto& entry : subsamples) {
  212. VAEncryptionSegmentInfo segment_info = {};
  213. segment_info.segment_start_offset = offset;
  214. segment_info.segment_length = entry.clear_bytes + entry.cypher_bytes;
  215. memcpy(segment_info.aes_cbc_iv_or_ctr, iv.data(),
  216. DecryptConfig::kDecryptionKeySize);
  217. if (ctr) {
  218. size_t partial_block_size =
  219. (DecryptConfig::kDecryptionKeySize -
  220. (total_cypher_size % DecryptConfig::kDecryptionKeySize)) %
  221. DecryptConfig::kDecryptionKeySize;
  222. segment_info.partial_aes_block_size = partial_block_size;
  223. if (entry.cypher_bytes > partial_block_size) {
  224. // If we are finishing a block, increment the counter.
  225. if (partial_block_size)
  226. ctr128_inc64(iv.data());
  227. // Increment the counter for every complete block we are adding.
  228. for (size_t block = 0;
  229. block < (entry.cypher_bytes - partial_block_size) /
  230. DecryptConfig::kDecryptionKeySize;
  231. ++block)
  232. ctr128_inc64(iv.data());
  233. }
  234. total_cypher_size += entry.cypher_bytes;
  235. }
  236. segment_info.init_byte_length = entry.clear_bytes;
  237. offset += entry.clear_bytes + entry.cypher_bytes;
  238. segments->emplace_back(std::move(segment_info));
  239. }
  240. memcpy(crypto_params->wrapped_decrypt_blob,
  241. hw_key_data_map_[decrypt_config_->key_id()].data(),
  242. DecryptConfig::kDecryptionKeySize);
  243. crypto_params->key_blob_size = DecryptConfig::kDecryptionKeySize;
  244. crypto_params->segment_info = &segments->front();
  245. return protected_session_state_;
  246. }
  247. #endif // if BUILDFLAG(IS_CHROMEOS_ASH)
  248. bool VaapiVideoDecoderDelegate::NeedsProtectedSessionRecovery() {
  249. if (!IsEncryptedSession() || !vaapi_wrapper_->IsProtectedSessionDead() ||
  250. performing_recovery_) {
  251. return false;
  252. }
  253. RecoverProtectedSession();
  254. return true;
  255. }
  256. void VaapiVideoDecoderDelegate::ProtectedDecodedSucceeded() {
  257. performing_recovery_ = false;
  258. }
  259. std::string VaapiVideoDecoderDelegate::GetDecryptKeyId() const {
  260. DCHECK(decrypt_config_);
  261. return decrypt_config_->key_id();
  262. }
  263. void VaapiVideoDecoderDelegate::OnGetHwConfigData(
  264. bool success,
  265. const std::vector<uint8_t>& config_data) {
  266. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  267. if (!success) {
  268. protected_session_state_ = ProtectedSessionState::kFailed;
  269. on_protected_session_update_cb_.Run(false);
  270. return;
  271. }
  272. hw_identifier_.clear();
  273. if (!vaapi_wrapper_->CreateProtectedSession(encryption_scheme_, config_data,
  274. &hw_identifier_)) {
  275. LOG(ERROR) << "Failed to setup protected session";
  276. protected_session_state_ = ProtectedSessionState::kFailed;
  277. on_protected_session_update_cb_.Run(false);
  278. return;
  279. }
  280. protected_session_state_ = ProtectedSessionState::kCreated;
  281. on_protected_session_update_cb_.Run(true);
  282. }
  283. void VaapiVideoDecoderDelegate::OnGetHwKeyData(
  284. const std::string& key_id,
  285. Decryptor::Status status,
  286. const std::vector<uint8_t>& key_data) {
  287. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  288. // There's a special case here where we are updating usage times/checking on
  289. // key validity, and in that case the key is already in the map.
  290. if (base::Contains(hw_key_data_map_, key_id)) {
  291. if (status == Decryptor::Status::kSuccess)
  292. return;
  293. // This key is no longer valid, decryption will fail, so stop playback
  294. // now. This key should have been renewed by the CDM instead.
  295. LOG(ERROR) << "CDM has lost key information, stopping playback";
  296. protected_session_state_ = ProtectedSessionState::kFailed;
  297. on_protected_session_update_cb_.Run(false);
  298. return;
  299. }
  300. if (status != Decryptor::Status::kSuccess) {
  301. // If it's a failure, then indicate so, otherwise if it's waiting for a key,
  302. // then we don't do anything since we will get called again when there's a
  303. // message about key availability changing.
  304. if (status == Decryptor::Status::kNoKey) {
  305. DVLOG(1) << "HW did not have key information, keep waiting for it";
  306. return;
  307. }
  308. LOG(ERROR) << "Failure getting the key data, fail overall";
  309. protected_session_state_ = ProtectedSessionState::kFailed;
  310. on_protected_session_update_cb_.Run(false);
  311. return;
  312. }
  313. if (key_data.size() != DecryptConfig::kDecryptionKeySize) {
  314. LOG(ERROR) << "Invalid key size returned of: " << key_data.size();
  315. protected_session_state_ = ProtectedSessionState::kFailed;
  316. on_protected_session_update_cb_.Run(false);
  317. return;
  318. }
  319. hw_key_data_map_[key_id] = key_data;
  320. on_protected_session_update_cb_.Run(true);
  321. }
  322. void VaapiVideoDecoderDelegate::RecoverProtectedSession() {
  323. LOG(WARNING) << "Protected session loss detected, initiating recovery";
  324. protected_session_state_ = ProtectedSessionState::kNeedsRecovery;
  325. hw_key_data_map_.clear();
  326. hw_identifier_.clear();
  327. vaapi_wrapper_->DestroyProtectedSession();
  328. #if BUILDFLAG(IS_CHROMEOS_ASH)
  329. if (chromeos_cdm_context_ && chromeos_cdm_context_->UsingArcCdm()) {
  330. // The ARC decoder doesn't handle the WaitingCB that'll get invoked so we
  331. // need to trigger a protected update ourselves in order to get decoding
  332. // running again.
  333. base::SequencedTaskRunnerHandle::Get()->PostTask(
  334. FROM_HERE,
  335. base::BindRepeating(on_protected_session_update_cb_, true));
  336. }
  337. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  338. }
  339. } // namespace media