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

media / renderers / video_frame_shared_image_cache.cc [blame]

// Copyright 2021 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/renderers/video_frame_shared_image_cache.h"

#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/common/resources/shared_image_format.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"

namespace media {

namespace {

// Returns multiplanar format equivalent of a VideoPixelFormat.
viz::SharedImageFormat VideoPixelFormatToSharedImageFormat(
    VideoPixelFormat video_format) {
  switch (video_format) {
    case PIXEL_FORMAT_NV12:
      return viz::MultiPlaneFormat::kNV12;
    case PIXEL_FORMAT_NV16:
      return viz::MultiPlaneFormat::kNV16;
    case PIXEL_FORMAT_NV24:
      return viz::MultiPlaneFormat::kNV24;
    case PIXEL_FORMAT_NV12A:
      return viz::MultiPlaneFormat::kNV12A;
    case PIXEL_FORMAT_P010LE:
      return viz::MultiPlaneFormat::kP010;
    case PIXEL_FORMAT_P210LE:
      return viz::MultiPlaneFormat::kP210;
    case PIXEL_FORMAT_P410LE:
      return viz::MultiPlaneFormat::kP410;
    case PIXEL_FORMAT_I420:
      return viz::MultiPlaneFormat::kI420;
    case PIXEL_FORMAT_I420A:
      return viz::MultiPlaneFormat::kI420A;
    default:
      NOTREACHED();
  }
}

}  // namespace

VideoFrameSharedImageCache::VideoFrameSharedImageCache() = default;

VideoFrameSharedImageCache::~VideoFrameSharedImageCache() {
  ReleaseCachedData();
}

void VideoFrameSharedImageCache::ReleaseCachedData() {
  // Don't destroy shared image we don't own.
  if (!shared_image_) {
    return;
  }

  auto* sii = provider_->SharedImageInterface();
  DCHECK(sii);
  if (shared_image_) {
    sii->DestroySharedImage(sync_token_, std::move(shared_image_));
  }
}

VideoFrameSharedImageCache::CachedData
VideoFrameSharedImageCache::GetSharedImage(
    const VideoFrame* video_frame,
    viz::RasterContextProvider* raster_context_provider,
    gpu::SharedImageUsageSet usage) {
  viz::SharedImageFormat format =
      VideoPixelFormatToSharedImageFormat(video_frame->format());
  CHECK(format.is_multi_plane());

  if (shared_image_ && provider_ == raster_context_provider) {
    // Return the cached shared image if it is the same video frame.
    if (video_frame_id_ == video_frame->unique_id()) {
      return {shared_image_, sync_token_, Status::kMatchedVideoFrameId};
    }
    // Return the cached shared image if the video frame data matches the shared
    // image data.
    if (video_frame->coded_size() == shared_image_->size() &&
        video_frame->ColorSpace() == shared_image_->color_space() &&
        format == shared_image_->format() && usage == shared_image_->usage()) {
      return {shared_image_, sync_token_, Status::kMatchedSharedImageMetaData};
    }
  }

  // If we have cached shared image but the provider or video has changed we
  // need to release shared image created on the old context and recreate them.
  ReleaseCachedData();
  provider_ = raster_context_provider;
  CHECK(provider_);
  auto* sii = provider_->SharedImageInterface();
  CHECK(sii);

  // Create a multiplanar shared image to upload the data to.
  shared_image_ = sii->CreateSharedImage(
      {format, video_frame->coded_size(), video_frame->ColorSpace(),
       kTopLeft_GrSurfaceOrigin, kUnpremul_SkAlphaType, usage, "VideoFrameYUV"},
      gpu::kNullSurfaceHandle);
  CHECK(shared_image_);
  video_frame_id_ = video_frame->unique_id();
  sync_token_ = sii->GenUnverifiedSyncToken();

  return {shared_image_, sync_token_, Status::kCreatedNewSharedImage};
}

void VideoFrameSharedImageCache::UpdateSyncToken(
    const gpu::SyncToken& sync_token) {
  sync_token_ = sync_token;
}

VideoFrameSharedImageCache::CachedData::CachedData(
    scoped_refptr<gpu::ClientSharedImage> shared_image,
    const gpu::SyncToken& sync_token,
    Status status)
    : shared_image(std::move(shared_image)),
      sync_token(sync_token),
      status(status) {}
VideoFrameSharedImageCache::CachedData::~CachedData() = default;

}  // namespace media