summaryrefslogtreecommitdiff
path: root/chromium/media/renderers/paint_canvas_video_renderer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/renderers/paint_canvas_video_renderer.cc')
-rw-r--r--chromium/media/renderers/paint_canvas_video_renderer.cc440
1 files changed, 259 insertions, 181 deletions
diff --git a/chromium/media/renderers/paint_canvas_video_renderer.cc b/chromium/media/renderers/paint_canvas_video_renderer.cc
index 21133386d89..a1923e2d963 100644
--- a/chromium/media/renderers/paint_canvas_video_renderer.cc
+++ b/chromium/media/renderers/paint_canvas_video_renderer.cc
@@ -49,6 +49,7 @@
// shown here to indicate where ideal conversions are currently missing.
#if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
SK_A32_SHIFT == 24
+#define OUTPUT_ARGB 1
#define LIBYUV_I400_TO_ARGB libyuv::I400ToARGB
#define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
#define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
@@ -86,8 +87,11 @@
// #define LIBYUV_U410_TO_ARGB libyuv::U410ToARGB
#define LIBYUV_NV12_TO_ARGB libyuv::NV12ToARGB
+
+#define LIBYUV_ABGR_TO_ARGB libyuv::ABGRToARGB
#elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
SK_A32_SHIFT == 24
+#define OUTPUT_ARGB 0
#define LIBYUV_I400_TO_ARGB libyuv::I400ToARGB
#define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
#define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
@@ -125,6 +129,8 @@
// #define LIBYUV_U410_TO_ARGB libyuv::U410ToABGR
#define LIBYUV_NV12_TO_ARGB libyuv::NV12ToABGR
+
+#define LIBYUV_ABGR_TO_ARGB libyuv::ARGBToABGR
#else
#error Unexpected Skia ARGB_8888 layout!
#endif
@@ -243,7 +249,6 @@ sk_sp<SkImage> WrapGLTexture(
GLenum target,
GLuint texture_id,
const gfx::Size& size,
- const gfx::ColorSpace& color_space,
viz::RasterContextProvider* raster_context_provider) {
GrGLTextureInfo texture_info;
texture_info.fID = texture_id;
@@ -254,10 +259,9 @@ sk_sp<SkImage> WrapGLTexture(
texture_info.fFormat = GL_RGBA8_OES;
GrBackendTexture backend_texture(size.width(), size.height(),
GrMipMapped::kNo, texture_info);
- return SkImage::MakeFromTexture(
+ return SkImage::MakeFromAdoptedTexture(
raster_context_provider->GrContext(), backend_texture,
- kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- color_space.ToSkColorSpace(), nullptr, nullptr);
+ kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
}
void VideoFrameCopyTextureOrSubTexture(gpu::gles2::GLES2Interface* gl,
@@ -314,7 +318,7 @@ void SynchronizeVideoFrameRead(scoped_refptr<VideoFrame> video_frame,
WaitAndReplaceSyncTokenClient client(ri);
video_frame->UpdateReleaseSyncToken(&client);
- if (video_frame->metadata()->read_lock_fences_enabled) {
+ if (video_frame->metadata().read_lock_fences_enabled) {
// |video_frame| must be kept alive during read operations.
DCHECK(context_support);
unsigned query_id = 0;
@@ -386,6 +390,29 @@ void ConvertVideoFrameToRGBPixelsTask(const VideoFrame* video_frame,
uint8_t* pixels = static_cast<uint8_t*>(rgb_pixels) +
row_bytes * chunk_start * rows_per_chunk;
+ if (format == PIXEL_FORMAT_ARGB || format == PIXEL_FORMAT_XRGB ||
+ format == PIXEL_FORMAT_ABGR || format == PIXEL_FORMAT_XBGR) {
+ DCHECK_LE(width, static_cast<int>(row_bytes));
+ const uint8_t* data = plane_meta[VideoFrame::kARGBPlane].data;
+
+ if ((OUTPUT_ARGB &&
+ (format == PIXEL_FORMAT_ARGB || format == PIXEL_FORMAT_XRGB)) ||
+ (!OUTPUT_ARGB &&
+ (format == PIXEL_FORMAT_ABGR || format == PIXEL_FORMAT_XBGR))) {
+ for (size_t i = 0; i < rows; i++) {
+ memcpy(pixels, data, width * 4);
+ pixels += row_bytes;
+ data += plane_meta[VideoFrame::kARGBPlane].stride;
+ }
+ } else {
+ LIBYUV_ABGR_TO_ARGB(plane_meta[VideoFrame::kARGBPlane].data,
+ plane_meta[VideoFrame::kARGBPlane].stride, pixels,
+ row_bytes, width, rows);
+ }
+ done->Run();
+ return;
+ }
+
// TODO(crbug.com/828599): This should default to BT.709 color space.
SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
video_frame->ColorSpace().ToSkYUVColorSpace(&color_space);
@@ -611,6 +638,7 @@ void ConvertVideoFrameToRGBPixelsTask(const VideoFrame* video_frame,
case PIXEL_FORMAT_P016LE:
case PIXEL_FORMAT_XR30:
case PIXEL_FORMAT_XB30:
+ case PIXEL_FORMAT_RGBAF16:
case PIXEL_FORMAT_UNKNOWN:
NOTREACHED() << "Only YUV formats and Y16 are supported, got: "
<< media::VideoPixelFormatToString(format);
@@ -638,31 +666,24 @@ bool ValidFormatForDirectUploading(GrGLenum format, unsigned int type) {
}
}
-bool VideoPixelFormatAsSkYUVAInfoPlanarConfig(
- VideoPixelFormat format,
- SkYUVAInfo::PlanarConfig* config) {
- // TODO(skbug.com/10632): Add more formats, e.g. I420A, NV12, NV21 when Skia
- // equivalents are added.
+std::tuple<SkYUVAInfo::PlaneConfig, SkYUVAInfo::Subsampling>
+VideoPixelFormatAsSkYUVAInfoValues(VideoPixelFormat format) {
// The 9, 10, and 12 bit formats could be added here if GetYUVAPlanes() were
- // updated to convert data to unorm16/float16.
+ // updated to convert data to unorm16/float16. Similarly, alpha planes and
+ // formats with interleaved planes (e.g. NV12) could be supported if that
+ // function were updated to not assume 3 separate Y, U, and V planes. Also,
+ // GpuImageDecodeCache would need be able to handle plane configurations
+ // other than 3 separate y, u, and v planes (crbug.com/910276).
switch (format) {
case PIXEL_FORMAT_I420:
- if (config) {
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_420;
- }
- return true;
+ return {SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k420};
case PIXEL_FORMAT_I422:
- if (config) {
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_422;
- }
- return true;
+ return {SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k422};
case PIXEL_FORMAT_I444:
- if (config) {
- *config = SkYUVAInfo::PlanarConfig::kY_U_V_444;
- }
- return true;
+ return {SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k444};
default:
- return false;
+ return {SkYUVAInfo::PlaneConfig::kUnknown,
+ SkYUVAInfo::Subsampling::kUnknown};
}
}
@@ -704,9 +725,11 @@ class VideoImageGenerator : public cc::PaintImageGenerator {
// is added for VideoImageGenerator.
return false;
#if 0
- SkYUVAInfo::PlanarConfig planar_config;
- if (!VideoPixelFormatAsSkYUVAInfoPlanarConfig(frame_->format(),
- &planar_config)) {
+ SkYUVAInfo::PlaneConfig plane_config;
+ SkYUVAInfo::Subsampling subsampling;
+ std::tie(plane_config, subsampling) =
+ VideoPixelFormatAsSkYUVAInfoValues(frame_->format());
+ if (plane_config == SkYUVAInfo::PlaneConfig::kUnknown) {
return false;
}
if (info) {
@@ -719,11 +742,12 @@ class VideoImageGenerator : public cc::PaintImageGenerator {
// We use the Y plane size because it may get rounded up to an even size.
// Our implementation of GetYUVAPlanes expects this.
gfx::Size y_size =
- VideoFrame::PlaneSize(frame_->format(), VideoFrame::kYPlane,
- gfx::Size(frame_->visible_rect().width(),
- frame_->visible_rect().height()));
- SkYUVAInfo yuva_info = SkYUVAInfo({y_size.width(), y_size.height()},
- planar_config, yuv_color_space);
+ VideoFrame::PlaneSizeInSamples(frame_->format(), VideoFrame::kYPlane,
+ gfx::Size(frame_->visible_rect().width(),
+ frame_->visible_rect().height()));
+ SkYUVAInfo yuva_info =
+ SkYUVAInfo({y_size.width(), y_size.height()}, plane_config,
+ subsampling, yuv_color_space);
*info = SkYUVAPixmapInfo(yuva_info, SkYUVAPixmapInfo::DataType::kUnorm8,
/* row bytes */ nullptr);
}
@@ -735,21 +759,23 @@ class VideoImageGenerator : public cc::PaintImageGenerator {
size_t frame_index,
uint32_t lazy_pixel_ref) override {
DCHECK_EQ(frame_index, 0u);
-
- if (!VideoPixelFormatAsSkYUVAInfoPlanarConfig(frame_->format(), nullptr)) {
- return false;
- }
-
- if (!pixmaps.plane(3).dimensions().isEmpty()) {
- return false;
+ DCHECK_EQ(pixmaps.numPlanes(), 3);
+
+ if (DCHECK_IS_ON()) {
+ SkYUVAInfo::PlaneConfig plane_config;
+ SkYUVAInfo::Subsampling subsampling;
+ std::tie(plane_config, subsampling) =
+ VideoPixelFormatAsSkYUVAInfoValues(frame_->format());
+ DCHECK_EQ(plane_config, pixmaps.yuvaInfo().planeConfig());
+ DCHECK_EQ(subsampling, pixmaps.yuvaInfo().subsampling());
}
for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
++plane) {
const gfx::Size size =
- VideoFrame::PlaneSize(frame_->format(), plane,
- gfx::Size(frame_->visible_rect().width(),
- frame_->visible_rect().height()));
+ VideoFrame::PlaneSizeInSamples(frame_->format(), plane,
+ gfx::Size(frame_->visible_rect().width(),
+ frame_->visible_rect().height()));
if (size.width() != pixmaps.plane(plane).width() ||
size.height() != pixmaps.plane(plane).height()) {
return false;
@@ -789,28 +815,67 @@ class VideoImageGenerator : public cc::PaintImageGenerator {
DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator);
};
-// TODO(jochin): Add support for all OOP-R specific APIs (eg. GetMailbox() and
-// GetSkImageViaReadback())
class VideoTextureBacking : public cc::TextureBacking {
public:
explicit VideoTextureBacking(
sk_sp<SkImage> sk_image,
+ const gpu::Mailbox& mailbox,
+ bool wraps_video_frame_texture,
scoped_refptr<viz::RasterContextProvider> raster_context_provider)
- : sk_image_(std::move(sk_image)) {
+ : sk_image_(std::move(sk_image)),
+ sk_image_info_(sk_image_->imageInfo()),
+ mailbox_(mailbox),
+ wraps_video_frame_texture_(wraps_video_frame_texture) {
raster_context_provider_ = std::move(raster_context_provider);
}
- const SkImageInfo& GetSkImageInfo() override {
- return sk_image_->imageInfo();
+ explicit VideoTextureBacking(
+ const gpu::Mailbox& mailbox,
+ const SkImageInfo& info,
+ bool wraps_video_frame_texture,
+ scoped_refptr<viz::RasterContextProvider> raster_context_provider)
+ : sk_image_info_(info),
+ mailbox_(mailbox),
+ wraps_video_frame_texture_(wraps_video_frame_texture) {
+ raster_context_provider_ = std::move(raster_context_provider);
+ }
+
+ ~VideoTextureBacking() override {
+ auto* ri = raster_context_provider_->RasterInterface();
+ if (!wraps_video_frame_texture_) {
+ gpu::SyncToken sync_token;
+ ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+ auto* sii = raster_context_provider_->SharedImageInterface();
+ sii->DestroySharedImage(sync_token, mailbox_);
+ }
}
+
+ const SkImageInfo& GetSkImageInfo() override { return sk_image_info_; }
gpu::Mailbox GetMailbox() const override { return mailbox_; }
sk_sp<SkImage> GetAcceleratedSkImage() override { return sk_image_; }
+ bool wraps_video_frame_texture() const { return wraps_video_frame_texture_; }
+ const scoped_refptr<viz::RasterContextProvider>& raster_context_provider()
+ const {
+ return raster_context_provider_;
+ }
+
sk_sp<SkImage> GetSkImageViaReadback() override {
- if (sk_image_) {
+ if (sk_image_)
return sk_image_->makeNonTextureImage();
- }
- return nullptr;
+
+ sk_sp<SkData> image_pixels =
+ SkData::MakeUninitialized(sk_image_info_.computeMinByteSize());
+ uint8_t* writable_pixels =
+ static_cast<uint8_t*>(image_pixels->writable_data());
+ gpu::raster::RasterInterface* ri =
+ raster_context_provider_->RasterInterface();
+ ri->ReadbackImagePixels(mailbox_, sk_image_info_,
+ sk_image_info_.minRowBytes(), 0, 0,
+ writable_pixels);
+ return SkImage::MakeRasterData(sk_image_info_, std::move(image_pixels),
+ sk_image_info_.minRowBytes());
}
+
bool readPixels(const SkImageInfo& dst_info,
void* dst_pixels,
size_t dst_row_bytes,
@@ -820,8 +885,13 @@ class VideoTextureBacking : public cc::TextureBacking {
return sk_image_->readPixels(dst_info, dst_pixels, dst_row_bytes, src_x,
src_y);
}
- return false;
+ gpu::raster::RasterInterface* ri =
+ raster_context_provider_->RasterInterface();
+ ri->ReadbackImagePixels(mailbox_, dst_info, dst_info.minRowBytes(), src_x,
+ src_y, dst_pixels);
+ return true;
}
+
void FlushPendingSkiaOps() override {
if (!raster_context_provider_ || !sk_image_)
return;
@@ -829,9 +899,19 @@ class VideoTextureBacking : public cc::TextureBacking {
}
private:
- const sk_sp<SkImage> sk_image_;
- const gpu::Mailbox mailbox_;
+ sk_sp<SkImage> sk_image_;
+ SkImageInfo sk_image_info_;
scoped_refptr<viz::RasterContextProvider> raster_context_provider_;
+
+ // This can be either the source VideoFrame's texture (if
+ // |wraps_video_frame_texture_| is true) or a newly allocated shared image
+ // (if |wraps_video_frame_texture_| is false) if a copy or conversion was
+ // necessary.
+ const gpu::Mailbox mailbox_;
+
+ // Whether |mailbox_| directly points to a texture of the VideoFrame
+ // (if true), or to an allocated shared image (if false).
+ const bool wraps_video_frame_texture_;
};
PaintCanvasVideoRenderer::PaintCanvasVideoRenderer()
@@ -864,7 +944,11 @@ void PaintCanvasVideoRenderer::Paint(
// frame has an unexpected format.
if (!video_frame.get() || video_frame->natural_size().IsEmpty() ||
!(media::IsYuvPlanar(video_frame->format()) ||
- video_frame->format() == media::PIXEL_FORMAT_Y16 ||
+ video_frame->format() == PIXEL_FORMAT_Y16 ||
+ video_frame->format() == PIXEL_FORMAT_ARGB ||
+ video_frame->format() == PIXEL_FORMAT_XRGB ||
+ video_frame->format() == PIXEL_FORMAT_ABGR ||
+ video_frame->format() == PIXEL_FORMAT_XBGR ||
video_frame->HasTextures())) {
cc::PaintFlags black_with_alpha_flags;
black_with_alpha_flags.setAlpha(flags.getAlpha());
@@ -883,21 +967,20 @@ void PaintCanvasVideoRenderer::Paint(
DCHECK(image);
base::Optional<ScopedSharedImageAccess> source_access;
- if (video_frame->HasTextures()) {
- DCHECK(!cache_->source_mailbox.IsZero());
- DCHECK(cache_->source_texture);
+ if (video_frame->HasTextures() && cache_->source_texture) {
+ DCHECK(cache_->texture_backing);
source_access.emplace(raster_context_provider->RasterInterface(),
- cache_->source_texture, cache_->source_mailbox);
+ cache_->source_texture,
+ cache_->texture_backing->GetMailbox());
}
cc::PaintFlags video_flags;
video_flags.setAlpha(flags.getAlpha());
video_flags.setBlendMode(flags.getBlendMode());
- video_flags.setFilterQuality(flags.getFilterQuality());
const bool need_rotation = video_transformation.rotation != VIDEO_ROTATION_0;
const bool need_scaling =
- dest_rect.size() != gfx::SizeF(image.width(), image.height());
+ dest_rect.size() != gfx::SizeF(video_frame->visible_rect().size());
const bool need_translation = !dest_rect.origin().IsOrigin();
// TODO(tmathmeyer): apply horizontal / vertical mirroring if needed.
bool need_transform = need_rotation || need_scaling || need_translation;
@@ -928,10 +1011,13 @@ void PaintCanvasVideoRenderer::Paint(
rotated_dest_size =
gfx::SizeF(rotated_dest_size.height(), rotated_dest_size.width());
}
- canvas->scale(SkFloatToScalar(rotated_dest_size.width() / image.width()),
- SkFloatToScalar(rotated_dest_size.height() / image.height()));
- canvas->translate(-SkFloatToScalar(image.width() * 0.5f),
- -SkFloatToScalar(image.height() * 0.5f));
+ canvas->scale(SkFloatToScalar(rotated_dest_size.width() /
+ video_frame->visible_rect().width()),
+ SkFloatToScalar(rotated_dest_size.height() /
+ video_frame->visible_rect().height()));
+ canvas->translate(
+ -SkFloatToScalar(video_frame->visible_rect().width() * 0.5f),
+ -SkFloatToScalar(video_frame->visible_rect().height() * 0.5f));
}
SkImageInfo info;
@@ -950,8 +1036,24 @@ void PaintCanvasVideoRenderer::Paint(
const size_t offset = info.computeOffset(origin.x(), origin.y(), row_bytes);
void* const pixels_offset = reinterpret_cast<char*>(pixels) + offset;
ConvertVideoFrameToRGBPixels(video_frame.get(), pixels_offset, row_bytes);
+ } else if (video_frame->HasTextures()) {
+ DCHECK_EQ(video_frame->coded_size(),
+ gfx::Size(image.width(), image.height()));
+ canvas->drawImageRect(
+ image, gfx::RectToSkRect(video_frame->visible_rect()),
+ SkRect::MakeWH(video_frame->visible_rect().width(),
+ video_frame->visible_rect().height()),
+ SkSamplingOptions(flags.getFilterQuality(),
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ &video_flags, SkCanvas::kStrict_SrcRectConstraint);
} else {
- canvas->drawImage(image, 0, 0, &video_flags);
+ DCHECK_EQ(video_frame->visible_rect().size(),
+ gfx::Size(image.width(), image.height()));
+ canvas->drawImage(
+ image, 0, 0,
+ SkSamplingOptions(flags.getFilterQuality(),
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ &video_flags);
}
if (need_transform)
@@ -968,9 +1070,9 @@ void PaintCanvasVideoRenderer::Paint(
raster_context_provider->ContextSupport());
}
// Because we are not retaining a reference to the VideoFrame, it would be
- // invalid for the cache to directly wrap its texture(s), as they will be
- // recycled.
- DCHECK(!cache_ || !cache_->wraps_video_frame_texture);
+ // invalid for the texture_backing to directly wrap its texture(s), as they
+ // will be recycled.
+ DCHECK(!CacheBackingWrapsTexture());
}
void PaintCanvasVideoRenderer::Copy(
@@ -1024,7 +1126,7 @@ scoped_refptr<VideoFrame> DownShiftHighbitVideoFrame(
ret->set_color_space(video_frame->ColorSpace());
// Copy all metadata.
// (May be enough to copy color space)
- ret->metadata()->MergeMetadataFrom(video_frame->metadata());
+ ret->metadata().MergeMetadataFrom(video_frame->metadata());
for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane; ++plane) {
int width = ret->row_bytes(plane);
@@ -1296,17 +1398,23 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
DCHECK(video_frame);
DCHECK(video_frame->HasTextures());
if (video_frame->NumTextures() > 1 ||
- video_frame->metadata()->read_lock_fences_enabled) {
+ video_frame->metadata().read_lock_fences_enabled) {
if (!raster_context_provider)
return false;
GrDirectContext* gr_context = raster_context_provider->GrContext();
- if (!gr_context)
+ if (!gr_context &&
+ !raster_context_provider->ContextCapabilities().supports_oop_raster)
return false;
// TODO(crbug.com/1108154): Expand this uploading path to macOS, linux
// chromeOS after collecting perf data and resolve failure cases.
#if defined(OS_WIN)
- // Try direct uploading path
- if (premultiply_alpha && level == 0) {
+ // Since skia always produces premultiply alpha outputs,
+ // trying direct uploading path when video format is opaque or premultiply
+ // alpha been requested. And dst texture mipLevel must be 0.
+ // TODO(crbug.com/1155003): Figure out whether premultiply options here are
+ // accurate.
+ if ((media::IsOpaque(video_frame->format()) || premultiply_alpha) &&
+ level == 0) {
if (UploadVideoFrameToGLTexture(raster_context_provider, destination_gl,
video_frame, target, texture,
internal_format, format, type, flip_y)) {
@@ -1321,7 +1429,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
}
DCHECK(cache_);
- DCHECK(!cache_->source_mailbox.IsZero());
+ DCHECK(cache_->texture_backing);
gpu::raster::RasterInterface* canvas_ri =
raster_context_provider->RasterInterface();
@@ -1331,10 +1439,10 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
canvas_ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
uint32_t intermediate_texture = SynchronizeAndImportMailbox(
- destination_gl, sync_token, cache_->source_mailbox);
+ destination_gl, sync_token, cache_->texture_backing->GetMailbox());
{
ScopedSharedImageAccess access(destination_gl, intermediate_texture,
- cache_->source_mailbox);
+ cache_->texture_backing->GetMailbox());
VideoFrameCopyTextureOrSubTexture(
destination_gl, cache_->coded_size, cache_->visible_rect,
intermediate_texture, target, texture, internal_format, format, type,
@@ -1352,7 +1460,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
// Because we are not retaining a reference to the VideoFrame, it would be
// invalid to keep the cache around if it directly wraps the VideoFrame
// texture(s), as they will be recycled.
- if (cache_->wraps_video_frame_texture)
+ if (cache_->texture_backing->wraps_video_frame_texture())
cache_.reset();
// Synchronize |video_frame| with the read operations in UpdateLastImage(),
@@ -1367,8 +1475,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
WaitAndReplaceSyncTokenClient client(destination_gl);
video_frame->UpdateReleaseSyncToken(&client);
}
- DCHECK(!cache_ || !cache_->wraps_video_frame_texture);
-
+ DCHECK(!CacheBackingWrapsTexture());
return true;
}
@@ -1386,8 +1493,7 @@ bool PaintCanvasVideoRenderer::UploadVideoFrameToGLTexture(
DCHECK(video_frame);
DCHECK(video_frame->HasTextures());
// Support uploading for NV12 and I420 video frame only.
- if (video_frame->format() != PIXEL_FORMAT_I420 &&
- video_frame->format() != PIXEL_FORMAT_NV12) {
+ if (!VideoFrameYUVConverter::IsVideoFrameFormatSupported(*video_frame)) {
return false;
}
@@ -1402,6 +1508,7 @@ bool PaintCanvasVideoRenderer::UploadVideoFrameToGLTexture(
return false;
}
+ // TODO(nazabris): Support OOP-R code path here that does not have GrContext.
if (!raster_context_provider || !raster_context_provider->GrContext())
return false;
@@ -1420,7 +1527,7 @@ bool PaintCanvasVideoRenderer::UploadVideoFrameToGLTexture(
destination_gl->GenUnverifiedSyncTokenCHROMIUM(
mailbox_holder.sync_token.GetData());
- if (!VideoFrameYUVConverter::ConvertYUVVideoFrameWithSkSurfaceNoCaching(
+ if (!VideoFrameYUVConverter::ConvertYUVVideoFrameToDstTextureNoCaching(
video_frame.get(), raster_context_provider, mailbox_holder,
internal_format, type, flip_y, true /* use visible_rect */)) {
return false;
@@ -1461,6 +1568,7 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrameForWebGL(
return false;
}
+ // TODO(nazabris): Support OOP-R code path here that does not have GrContext.
if (!raster_context_provider || !raster_context_provider->GrContext())
return false;
@@ -1498,7 +1606,7 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrameForWebGL(
WaitAndReplaceSyncTokenClient client(source_ri);
video_frame->UpdateReleaseSyncToken(&client);
- DCHECK(!cache_ || !cache_->wraps_video_frame_texture);
+ DCHECK(!CacheBackingWrapsTexture());
return true;
}
@@ -1519,7 +1627,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture(
return false;
}
- if (video_frame.format() != media::PIXEL_FORMAT_I420) {
+ if (!VideoFrameYUVConverter::IsVideoFrameFormatSupported(video_frame)) {
return false;
}
// Could handle NV12 here as well. See NewSkImageFromVideoFrameYUV.
@@ -1672,38 +1780,17 @@ void PaintCanvasVideoRenderer::ResetCache() {
PaintCanvasVideoRenderer::Cache::Cache(int frame_id) : frame_id(frame_id) {}
-PaintCanvasVideoRenderer::Cache::~Cache() {
- if (!raster_context_provider)
- return;
-
- DCHECK(!source_mailbox.IsZero());
- DCHECK(source_texture);
- auto* ri = raster_context_provider->RasterInterface();
- if (!texture_ownership_in_skia)
- ri->DeleteGpuRasterTexture(source_texture);
- if (!wraps_video_frame_texture) {
- gpu::SyncToken sync_token;
- ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
- auto* sii = raster_context_provider->SharedImageInterface();
- sii->DestroySharedImage(sync_token, source_mailbox);
- }
-}
+PaintCanvasVideoRenderer::Cache::~Cache() = default;
bool PaintCanvasVideoRenderer::Cache::Recycle() {
- if (!texture_ownership_in_skia)
- return true;
+ DCHECK(!texture_backing->wraps_video_frame_texture());
- if (!paint_image.HasExclusiveTextureAccess())
+ paint_image = cc::PaintImage();
+ if (!texture_backing->unique())
return false;
// Flush any pending GPU work using this texture.
- paint_image.FlushPendingSkiaOps();
-
- paint_image = cc::PaintImage();
- // We need a new texture ID because skia will destroy the previous one with
- // the SkImage.
- texture_ownership_in_skia = false;
- source_texture = 0;
+ texture_backing->FlushPendingSkiaOps();
return true;
}
@@ -1711,9 +1798,9 @@ bool PaintCanvasVideoRenderer::UpdateLastImage(
scoped_refptr<VideoFrame> video_frame,
viz::RasterContextProvider* raster_context_provider,
bool allow_wrap_texture) {
- DCHECK(!cache_ || !cache_->wraps_video_frame_texture);
+ DCHECK(!CacheBackingWrapsTexture());
if (!cache_ || video_frame->unique_id() != cache_->frame_id ||
- cache_->source_mailbox.IsZero()) {
+ !cache_->paint_image) {
auto paint_image_builder =
cc::PaintImageBuilder::WithDefault()
.set_id(renderer_stable_id_)
@@ -1727,115 +1814,99 @@ bool PaintCanvasVideoRenderer::UpdateLastImage(
// could cause problems since the pool of VideoFrames has a fixed size.
if (video_frame->HasTextures()) {
DCHECK(raster_context_provider);
- DCHECK(raster_context_provider->GrContext());
+ bool supports_oop_raster =
+ raster_context_provider->ContextCapabilities().supports_oop_raster;
+ DCHECK(supports_oop_raster || raster_context_provider->GrContext());
auto* ri = raster_context_provider->RasterInterface();
DCHECK(ri);
+ bool wraps_video_frame_texture = false;
+ gpu::Mailbox mailbox;
if (allow_wrap_texture && video_frame->NumTextures() == 1) {
cache_.emplace(video_frame->unique_id());
const gpu::MailboxHolder& holder =
GetVideoFrameMailboxHolder(video_frame.get());
- cache_->source_mailbox = holder.mailbox;
+ mailbox = holder.mailbox;
ri->WaitSyncTokenCHROMIUM(holder.sync_token.GetConstData());
- cache_->wraps_video_frame_texture = true;
+ wraps_video_frame_texture = true;
} else {
- if (cache_ &&
- cache_->raster_context_provider == raster_context_provider &&
+ if (cache_ && cache_->texture_backing &&
+ cache_->texture_backing->raster_context_provider() ==
+ raster_context_provider &&
cache_->coded_size == video_frame->coded_size() &&
cache_->Recycle()) {
// We can reuse the shared image from the previous cache.
cache_->frame_id = video_frame->unique_id();
+ mailbox = cache_->texture_backing->GetMailbox();
} else {
cache_.emplace(video_frame->unique_id());
auto* sii = raster_context_provider->SharedImageInterface();
-
// TODO(nazabris): Sort out what to do when GLES2 is needed but the
// cached shared image is created without it.
uint32_t flags =
gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER;
- if (raster_context_provider->ContextCapabilities()
- .supports_oop_raster) {
+ if (supports_oop_raster) {
flags |= gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
}
- cache_->source_mailbox = sii->CreateSharedImage(
+ mailbox = sii->CreateSharedImage(
viz::ResourceFormat::RGBA_8888, video_frame->coded_size(),
gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
flags, gpu::kNullSurfaceHandle);
ri->WaitSyncTokenCHROMIUM(
sii->GenUnverifiedSyncToken().GetConstData());
}
-
- DCHECK(!cache_->texture_ownership_in_skia);
if (video_frame->NumTextures() == 1) {
auto frame_mailbox =
SynchronizeVideoFrameSingleMailbox(ri, video_frame.get());
- ri->CopySubTexture(
- frame_mailbox, cache_->source_mailbox, GL_TEXTURE_2D, 0, 0, 0, 0,
- video_frame->coded_size().width(),
- video_frame->coded_size().height(), GL_FALSE, GL_FALSE);
+ ri->CopySubTexture(frame_mailbox, mailbox, GL_TEXTURE_2D, 0, 0, 0, 0,
+ video_frame->coded_size().width(),
+ video_frame->coded_size().height(), GL_FALSE,
+ GL_FALSE);
} else {
- gpu::MailboxHolder dest_holder{cache_->source_mailbox,
- gpu::SyncToken(), GL_TEXTURE_2D};
+ gpu::MailboxHolder dest_holder{mailbox, gpu::SyncToken(),
+ GL_TEXTURE_2D};
VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching(
video_frame.get(), raster_context_provider, dest_holder);
}
- raster_context_provider->GrContext()->flushAndSubmit();
+ if (!supports_oop_raster)
+ raster_context_provider->GrContext()->flushAndSubmit();
}
- // TODO(jochin): Don't always generate SkImage here.
- DCHECK(cache_->source_texture == 0);
- cache_->source_texture =
- ri->CreateAndConsumeForGpuRaster(cache_->source_mailbox);
-
- // TODO(nazabris): Handle scoped access correctly. This follows the
- // current pattern but is most likely bugged. Access should last for the
- // lifetime of the SkImage.
- ScopedSharedImageAccess(ri, cache_->source_texture,
- cache_->source_mailbox);
- auto source_image =
- WrapGLTexture(cache_->wraps_video_frame_texture
- ? video_frame->mailbox_holder(0).texture_target
- : GL_TEXTURE_2D,
- cache_->source_texture, video_frame->coded_size(),
- video_frame->ColorSpace(), raster_context_provider);
- if (!source_image) {
- // Couldn't create the SkImage.
- cache_.reset();
- return false;
- }
- cache_->raster_context_provider = raster_context_provider;
cache_->coded_size = video_frame->coded_size();
cache_->visible_rect = video_frame->visible_rect();
- GrDirectContext* direct =
- GrAsDirectContext(raster_context_provider->GrContext());
- sk_sp<SkImage> source_subset = source_image->makeSubset(
- gfx::RectToSkIRect(cache_->visible_rect), direct);
- if (source_subset) {
- // We use the flushPendingGrContextIO = true so we can flush any pending
- // GPU work on the GrContext to ensure that skia exectues the work for
- // generating the subset and it can be safely destroyed.
- GrBackendTexture image_backend =
- source_image->getBackendTexture(/*flushPendingGrContextIO*/ true);
- GrBackendTexture subset_backend =
- source_subset->getBackendTexture(/*flushPendingGrContextIO*/ true);
-#if DCHECK_IS_ON()
- GrGLTextureInfo backend_info;
- if (image_backend.getGLTextureInfo(&backend_info))
- DCHECK_EQ(backend_info.fID, cache_->source_texture);
-#endif
- if (subset_backend.isValid() &&
- subset_backend.isSameTexture(image_backend)) {
- cache_->texture_ownership_in_skia = true;
- source_subset = SkImage::MakeFromAdoptedTexture(
- cache_->raster_context_provider->GrContext(), image_backend,
- kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
- kPremul_SkAlphaType, source_image->imageInfo().refColorSpace());
+ if (!cache_->texture_backing) {
+ if (supports_oop_raster) {
+ SkImageInfo sk_image_info =
+ SkImageInfo::Make(gfx::SizeToSkISize(cache_->coded_size),
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ cache_->texture_backing = sk_make_sp<VideoTextureBacking>(
+ mailbox, sk_image_info, wraps_video_frame_texture,
+ raster_context_provider);
+ } else {
+ cache_->source_texture = ri->CreateAndConsumeForGpuRaster(mailbox);
+
+ // TODO(nazabris): Handle scoped access correctly. This follows the
+ // current pattern but is most likely bugged. Access should last for
+ // the lifetime of the SkImage.
+ ScopedSharedImageAccess(ri, cache_->source_texture, mailbox);
+ auto source_image =
+ WrapGLTexture(wraps_video_frame_texture
+ ? video_frame->mailbox_holder(0).texture_target
+ : GL_TEXTURE_2D,
+ cache_->source_texture, video_frame->coded_size(),
+ raster_context_provider);
+ if (!source_image) {
+ // Couldn't create the SkImage.
+ cache_.reset();
+ return false;
+ }
+ cache_->texture_backing = sk_make_sp<VideoTextureBacking>(
+ std::move(source_image), mailbox, wraps_video_frame_texture,
+ raster_context_provider);
}
}
paint_image_builder.set_texture_backing(
- sk_sp<VideoTextureBacking>(new VideoTextureBacking(
- std::move(source_subset), raster_context_provider)),
- cc::PaintImage::GetNextContentId());
+ cache_->texture_backing, cc::PaintImage::GetNextContentId());
} else {
cache_.emplace(video_frame->unique_id());
paint_image_builder.set_paint_image_generator(
@@ -1843,7 +1914,7 @@ bool PaintCanvasVideoRenderer::UpdateLastImage(
}
cache_->paint_image = paint_image_builder.TakePaintImage();
if (!cache_->paint_image) {
- // Couldn't create the SkImage.
+ // Couldn't create the PaintImage.
cache_.reset();
return false;
}
@@ -1876,7 +1947,9 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrame(
}
PaintCanvasVideoRenderer::YUVTextureCache::YUVTextureCache() = default;
-PaintCanvasVideoRenderer::YUVTextureCache::~YUVTextureCache() = default;
+PaintCanvasVideoRenderer::YUVTextureCache::~YUVTextureCache() {
+ Reset();
+}
void PaintCanvasVideoRenderer::YUVTextureCache::Reset() {
if (mailbox.IsZero())
@@ -1906,4 +1979,9 @@ gfx::Size PaintCanvasVideoRenderer::LastImageDimensionsForTesting() {
return gfx::Size(cache_->paint_image.width(), cache_->paint_image.height());
}
+bool PaintCanvasVideoRenderer::CacheBackingWrapsTexture() const {
+ return cache_ && cache_->texture_backing &&
+ cache_->texture_backing->wraps_video_frame_texture();
+}
+
} // namespace media