-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/filters/decrypting_video_decoder.h"
-#include "base/bind.h"
-#include "base/callback_helpers.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
+#include "base/task/bind_post_task.h"
+#include "base/task/sequenced_task_runner.h"
#include "base/trace_event/trace_event.h"
-#include "media/base/bind_to_current_loop.h"
#include "media/base/cdm_context.h"
#include "media/base/decoder_buffer.h"
#include "media/base/media_log.h"
DCHECK(!reset_cb_);
DCHECK(config.IsValidConfig());
- init_cb_ = BindToCurrentLoop(std::move(init_cb));
+ init_cb_ = base::BindPostTaskToCurrentDefault(std::move(init_cb));
if (!cdm_context) {
// Once we have a CDM context, one should always be present.
DCHECK(!support_clear_content_);
- std::move(init_cb_).Run(StatusCode::kDecoderMissingCdmForEncryptedContent);
+ std::move(init_cb_).Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
return;
}
if (!config.is_encrypted() && !support_clear_content_) {
- std::move(init_cb_).Run(StatusCode::kClearContentUnsupported);
+ std::move(init_cb_).Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
return;
}
// the decryptor for clear content as well.
support_clear_content_ = true;
- output_cb_ = BindToCurrentLoop(output_cb);
+ output_cb_ = base::BindPostTaskToCurrentDefault(output_cb);
config_ = config;
DCHECK(waiting_cb);
if (state_ == kUninitialized) {
if (!cdm_context->GetDecryptor()) {
DVLOG(1) << __func__ << ": no decryptor";
- std::move(init_cb_).Run(StatusCode::kDecoderFailedInitialization);
+ std::move(init_cb_).Run(DecoderStatus::Codes::kUnsupportedEncryptionMode);
return;
}
state_ = kPendingDecoderInit;
decryptor_->InitializeVideoDecoder(
- config_, BindToCurrentLoop(
+ config_, base::BindPostTaskToCurrentDefault(
base::BindOnce(&DecryptingVideoDecoder::FinishInitialization,
weak_factory_.GetWeakPtr())));
}
DCHECK(decode_cb);
CHECK(!decode_cb_) << "Overlapping decodes are not supported.";
- decode_cb_ = BindToCurrentLoop(std::move(decode_cb));
+ decode_cb_ = base::BindPostTaskToCurrentDefault(std::move(decode_cb));
if (state_ == kError) {
- std::move(decode_cb_).Run(DecodeStatus::DECODE_ERROR);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kPlatformDecodeFailure);
return;
}
// Return empty frames if decoding has finished.
if (state_ == kDecodeFinished) {
- std::move(decode_cb_).Run(DecodeStatus::OK);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kOk);
return;
}
+ // One time set of `has_clear_lead_`.
+ if (!has_clear_lead_.has_value()) {
+ has_clear_lead_ = !buffer->end_of_stream() && !buffer->decrypt_config();
+ }
+
+ // Although the stream may switch from clear to encrypted to clear multiple
+ // times (e.g ad-insertions), we only log to the Media log the first switch
+ // from clear to encrypted.
+ if (HasClearLead() && !switched_clear_to_encrypted_ &&
+ !buffer->end_of_stream() && buffer->is_encrypted()) {
+ MEDIA_LOG(INFO, media_log_)
+ << "First switch from clear to encrypted buffers.";
+ switched_clear_to_encrypted_ = true;
+ }
+
pending_buffer_to_decode_ = std::move(buffer);
state_ = kPendingDecode;
DecodePendingBuffer();
DCHECK(!init_cb_); // No Reset() during pending initialization.
DCHECK(!reset_cb_);
- reset_cb_ = BindToCurrentLoop(std::move(closure));
+ reset_cb_ = base::BindPostTaskToCurrentDefault(std::move(closure));
decryptor_->ResetDecoder(Decryptor::kVideo);
CompleteWaitingForDecryptionKey();
DCHECK(decode_cb_);
pending_buffer_to_decode_.reset();
- std::move(decode_cb_).Run(DecodeStatus::ABORTED);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kAborted);
}
DCHECK(!decode_cb_);
}
pending_buffer_to_decode_.reset();
if (init_cb_)
- std::move(init_cb_).Run(StatusCode::kDecoderInitializeNeverCompleted);
+ std::move(init_cb_).Run(DecoderStatus::Codes::kInterrupted);
if (decode_cb_)
- std::move(decode_cb_).Run(DecodeStatus::ABORTED);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kAborted);
if (reset_cb_)
std::move(reset_cb_).Run();
}
if (!success) {
DVLOG(1) << __func__ << ": failed to init video decoder on decryptor";
- std::move(init_cb_).Run(StatusCode::kDecoderInitializeNeverCompleted);
+ // TODO(*) Is there a better reason? Should this method itself take a
+ // status?
+ std::move(init_cb_).Run(DecoderStatus::Codes::kFailed);
decryptor_ = nullptr;
event_cb_registration_.reset();
state_ = kError;
// Success!
state_ = kIdle;
- std::move(init_cb_).Run(OkStatus());
+ std::move(init_cb_).Run(DecoderStatus::Codes::kOk);
}
void DecryptingVideoDecoder::DecodePendingBuffer() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(state_, kPendingDecode) << state_;
+ auto& buffer = pending_buffer_to_decode_;
+
// Note: Traces require a unique ID per decode, if we ever support multiple
// in flight decodes, the trace begin+end macros need the same unique id.
DCHECK_EQ(GetMaxDecodeRequests(), 1);
- TRACE_EVENT_ASYNC_BEGIN1(
+ const bool is_end_of_stream = buffer->end_of_stream();
+ const bool is_encrypted = !is_end_of_stream && buffer->decrypt_config();
+ const auto timestamp_us =
+ is_end_of_stream ? 0 : buffer->timestamp().InMicroseconds();
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
"media", "DecryptingVideoDecoder::DecodePendingBuffer", this,
- "timestamp_us",
- pending_buffer_to_decode_->end_of_stream()
- ? 0
- : pending_buffer_to_decode_->timestamp().InMicroseconds());
+ "is_encrypted", is_encrypted, "timestamp_us", timestamp_us);
+
+ if (!DecoderBuffer::DoSubsamplesMatch(*buffer)) {
+ MEDIA_LOG(ERROR, media_log_)
+ << "DecryptingVideoDecoder: Subsamples for Buffer do not match";
+ state_ = kError;
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kPlatformDecodeFailure);
+ return;
+ }
decryptor_->DecryptAndDecodeVideo(
- pending_buffer_to_decode_,
- BindToCurrentLoop(base::BindRepeating(
+ buffer,
+ base::BindPostTaskToCurrentDefault(base::BindRepeating(
&DecryptingVideoDecoder::DeliverFrame, weak_factory_.GetWeakPtr())));
}
std::move(pending_buffer_to_decode_);
if (reset_cb_) {
- std::move(decode_cb_).Run(DecodeStatus::ABORTED);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kAborted);
DoReset();
return;
}
DVLOG(2) << "DeliverFrame() - kError";
MEDIA_LOG(ERROR, media_log_) << GetDecoderType() << ": decode error";
state_ = kError;
- std::move(decode_cb_).Run(DecodeStatus::DECODE_ERROR);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kPlatformDecodeFailure);
return;
}
return;
}
- TRACE_EVENT_ASYNC_BEGIN0(
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
"media", "DecryptingVideoDecoder::WaitingForDecryptionKey", this);
state_ = kWaitingForKey;
waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
DVLOG(2) << "DeliverFrame() - kNeedMoreData";
state_ = scoped_pending_buffer_to_decode->end_of_stream() ? kDecodeFinished
: kIdle;
- std::move(decode_cb_).Run(DecodeStatus::OK);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kOk);
return;
}
}
state_ = kIdle;
- std::move(decode_cb_).Run(DecodeStatus::OK);
+ std::move(decode_cb_).Run(DecoderStatus::Codes::kOk);
}
void DecryptingVideoDecoder::OnCdmContextEvent(CdmContext::Event event) {
void DecryptingVideoDecoder::CompletePendingDecode(Decryptor::Status status) {
DCHECK_EQ(state_, kPendingDecode);
- TRACE_EVENT_ASYNC_END1("media", "DecryptingVideoDecoder::DecodePendingBuffer",
- this, "status", Decryptor::GetStatusName(status));
+ TRACE_EVENT_NESTABLE_ASYNC_END1(
+ "media", "DecryptingVideoDecoder::DecodePendingBuffer", this, "status",
+ Decryptor::GetStatusName(status));
}
void DecryptingVideoDecoder::CompleteWaitingForDecryptionKey() {
DCHECK_EQ(state_, kWaitingForKey);
- TRACE_EVENT_ASYNC_END0(
+ TRACE_EVENT_NESTABLE_ASYNC_END0(
"media", "DecryptingVideoDecoder::WaitingForDecryptionKey", this);
}