blob: 81ec0c7cd6f4e1bf05309a5eedda29ff47dfe12c [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "media/base/video_frame.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/webcodecs/video_frame_monitor.h"
#include "third_party/blink/renderer/modules/webcodecs/webcodecs_logger.h"
#include "third_party/skia/include/core/SkImage.h"
namespace blink {
namespace {
base::TimeDelta GetPreferredTimestamp(bool prefer_capture_timestamp,
const media::VideoFrame& video_frame) {
if (prefer_capture_timestamp) {
if (video_frame.metadata().capture_begin_time) {
return *video_frame.metadata().capture_begin_time - base::TimeTicks();
}
if (video_frame.metadata().reference_time) {
return *video_frame.metadata().reference_time - base::TimeTicks();
}
}
return video_frame.timestamp();
}
} // namespace
VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
ExecutionContext* context,
std::string monitoring_source_id,
bool prefer_capture_timestamp)
: frame_(std::move(frame)),
monitoring_source_id_(std::move(monitoring_source_id)),
timestamp_(GetPreferredTimestamp(prefer_capture_timestamp, *frame_)),
duration_(frame_->metadata().frame_duration) {
DCHECK(frame_);
DCHECK(context);
close_auditor_ = WebCodecsLogger::From(*context).GetCloseAuditor();
DCHECK(close_auditor_);
MaybeMonitorOpenFrame();
}
VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
sk_sp<SkImage> sk_image,
ExecutionContext* context,
std::string monitoring_source_id,
bool use_capture_timestamp)
: VideoFrameHandle(std::move(frame),
context,
std::move(monitoring_source_id),
use_capture_timestamp) {
sk_image_ = std::move(sk_image);
}
VideoFrameHandle::VideoFrameHandle(
scoped_refptr<media::VideoFrame> frame,
sk_sp<SkImage> sk_image,
base::TimeDelta timestamp,
scoped_refptr<WebCodecsLogger::VideoFrameCloseAuditor> close_auditor,
std::string monitoring_source_id)
: sk_image_(std::move(sk_image)),
frame_(std::move(frame)),
close_auditor_(std::move(close_auditor)),
monitoring_source_id_(std::move(monitoring_source_id)),
timestamp_(timestamp),
duration_(frame_->metadata().frame_duration) {
DCHECK(frame_);
MaybeMonitorOpenFrame();
}
VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
sk_sp<SkImage> sk_image,
base::TimeDelta timestamp,
std::string monitoring_source_id)
: sk_image_(std::move(sk_image)),
frame_(std::move(frame)),
monitoring_source_id_(std::move(monitoring_source_id)),
timestamp_(timestamp),
duration_(frame_->metadata().frame_duration) {
DCHECK(frame_);
MaybeMonitorOpenFrame();
}
VideoFrameHandle::VideoFrameHandle(scoped_refptr<media::VideoFrame> frame,
sk_sp<SkImage> sk_image,
std::string monitoring_source_id)
: VideoFrameHandle(frame,
sk_image,
frame->timestamp(),
monitoring_source_id) {}
VideoFrameHandle::VideoFrameHandle(
scoped_refptr<media::VideoFrame> frame,
sk_sp<SkImage> sk_image,
scoped_refptr<WebCodecsLogger::VideoFrameCloseAuditor> close_auditor,
std::string monitoring_source_id)
: VideoFrameHandle(frame,
sk_image,
frame->timestamp(),
close_auditor,
monitoring_source_id) {}
VideoFrameHandle::~VideoFrameHandle() {
MaybeMonitorCloseFrame();
// If we still have a valid |close_auditor_|, Invalidate() was never
// called and corresponding frames never received a call to close() before
// being garbage collected.
if (close_auditor_)
close_auditor_->ReportUnclosedFrame();
}
scoped_refptr<media::VideoFrame> VideoFrameHandle::frame() {
base::AutoLock locker(lock_);
return frame_;
}
sk_sp<SkImage> VideoFrameHandle::sk_image() {
base::AutoLock locker(lock_);
return sk_image_;
}
void VideoFrameHandle::Invalidate() {
base::AutoLock locker(lock_);
InvalidateLocked();
}
void VideoFrameHandle::SetCloseOnClone() {
base::AutoLock locker(lock_);
close_on_clone_ = true;
}
scoped_refptr<VideoFrameHandle> VideoFrameHandle::Clone() {
base::AutoLock locker(lock_);
auto cloned_handle = frame_ ? base::MakeRefCounted<VideoFrameHandle>(
frame_, sk_image_, timestamp_,
close_auditor_, monitoring_source_id_)
: nullptr;
if (close_on_clone_)
InvalidateLocked();
return cloned_handle;
}
scoped_refptr<VideoFrameHandle> VideoFrameHandle::CloneForInternalUse() {
base::AutoLock locker(lock_);
return frame_ ? base::MakeRefCounted<VideoFrameHandle>(
frame_, sk_image_, timestamp_, monitoring_source_id_)
: nullptr;
}
void VideoFrameHandle::InvalidateLocked() {
MaybeMonitorCloseFrame();
frame_.reset();
sk_image_.reset();
close_auditor_.reset();
NotifyExpiredLocked();
}
void VideoFrameHandle::MaybeMonitorOpenFrame() {
if (frame_ && !monitoring_source_id_.empty()) {
VideoFrameMonitor::Instance().OnOpenFrame(monitoring_source_id_,
frame_->unique_id());
}
}
void VideoFrameHandle::MaybeMonitorCloseFrame() {
if (frame_ && !monitoring_source_id_.empty()) {
VideoFrameMonitor::Instance().OnCloseFrame(monitoring_source_id_,
frame_->unique_id());
}
}
bool VideoFrameHandle::WebGPURegisterExternalTextureExpireCallback(
WebGPUExternalTextureExpireCallback
webgpu_external_texture_expire_callback) {
base::AutoLock locker(lock_);
if (!frame_)
return false;
webgpu_external_texture_expire_callbacks_.push_back(
std::move(webgpu_external_texture_expire_callback));
return true;
}
void VideoFrameHandle::NotifyExpiredLocked() {
DCHECK(!frame_);
Vector<WebGPUExternalTextureExpireCallback>
webgpu_external_texture_expire_callbacks =
std::move(webgpu_external_texture_expire_callbacks_);
for (auto& callback : webgpu_external_texture_expire_callbacks) {
std::move(callback).Run();
}
}
} // namespace blink