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

media / renderers / video_frame_rgba_to_yuva_converter.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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "media/renderers/video_frame_rgba_to_yuva_converter.h"

#include "base/check.h"
#include "base/logging.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "media/base/simple_sync_token_client.h"

namespace media {

bool CopyRGBATextureToVideoFrame(
    viz::RasterContextProvider* provider,
    const gfx::Size& src_size,
    scoped_refptr<gpu::ClientSharedImage> src_shared_image,
    const gpu::SyncToken& acquire_sync_token,
    VideoFrame* dst_video_frame) {
  DCHECK_EQ(dst_video_frame->format(), PIXEL_FORMAT_NV12);
  CHECK(dst_video_frame->HasSharedImage());
  auto* ri = provider->RasterInterface();
  DCHECK(ri);

  // If context is lost for any reason e.g. creating shared image failed, we
  // cannot distinguish between OOP and non-OOP raster based on GrContext().
  if (ri->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
    DLOG(ERROR) << "Raster context lost.";
    return false;
  }

  // With OOP raster, if RGB->YUV conversion is unsupported, the CopySharedImage
  // calls will fail on the service side with no ability to detect failure on
  // the client side. Check for support here and early out if it's unsupported.
  if (!provider->ContextCapabilities().supports_rgb_to_yuv_conversion) {
    DVLOG(1) << "RGB->YUV conversion not supported";
    return false;
  }

  ri->WaitSyncTokenCHROMIUM(acquire_sync_token.GetConstData());

  auto dst_sync_token = dst_video_frame->acquire_sync_token();
  auto dst_mailbox = dst_video_frame->shared_image()->mailbox();
  ri->WaitSyncTokenCHROMIUM(dst_sync_token.GetConstData());

  // Note: the destination video frame can have a coded size that is larger
  // than that of the source video to account for alignment needs. In this
  // case, both this codepath and the the legacy codepath above stretch to
  // fill the destination. Cropping would clearly be more correct, but
  // implementing that behavior in CopySharedImage() for the MultiplanarSI
  // case resulted in pixeltest failures due to pixel bleeding around image
  // borders that we weren't able to resolve (see crbug.com/1451025 for
  // details).
  // TODO(crbug.com/40270413): Update this comment when we resolve that bug
  // and change CopySharedImage() to crop rather than stretch.
  ri->CopySharedImage(src_shared_image->mailbox(), dst_mailbox, 0, 0, 0, 0,
                      src_size.width(), src_size.height());
  ri->Flush();

  // Make access to the `dst_video_frame` wait on copy completion. We also
  // update the ReleaseSyncToken here since it's used when the underlying
  // GpuMemoryBuffer and SharedImage resources are returned to the pool.
  gpu::SyncToken completion_sync_token;
  ri->GenUnverifiedSyncTokenCHROMIUM(completion_sync_token.GetData());
  SimpleSyncTokenClient simple_client(completion_sync_token);
  dst_video_frame->UpdateAcquireSyncToken(&simple_client);
  dst_video_frame->UpdateReleaseSyncToken(&simple_client);
  return true;
}

}  // namespace media