From 591913ea8a59426be9902599cec129445804c8d7 Mon Sep 17 00:00:00 2001 From: Hou Qi Date: Fri, 13 Sep 2024 23:09:35 +0900 Subject: [PATCH 12/19] V4L2VideoDecoder: Support tile to linear transform for amphion Upstream-Status: Inappropriate [NXP specific] --- media/gpu/v4l2/BUILD.gn | 1 + media/gpu/v4l2/v4l2_queue.cc | 211 ++++++++++++++++++++++++++++++++++- media/gpu/v4l2/v4l2_queue.h | 1 + 3 files changed, 209 insertions(+), 4 deletions(-) diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn index 0aa466ba9cec5..836ee0bc7504c 100644 --- a/media/gpu/v4l2/BUILD.gn +++ b/media/gpu/v4l2/BUILD.gn @@ -92,6 +92,7 @@ source_set("v4l2") { "EGL", "GLESv2", ] + libs += [ "g2d" ] configs += [ "//third_party/libyuv:libyuv_config" ] diff --git a/media/gpu/v4l2/v4l2_queue.cc b/media/gpu/v4l2/v4l2_queue.cc index de74d0da308c3..945e7a7df9b93 100644 --- a/media/gpu/v4l2/v4l2_queue.cc +++ b/media/gpu/v4l2/v4l2_queue.cc @@ -20,6 +20,11 @@ #include "media/gpu/chromeos/platform_video_frame_utils.h" #include "media/gpu/macros.h" +#include "g2d.h" +#include "g2dExt.h" +#include +#include + namespace media { namespace { @@ -189,6 +194,11 @@ class V4L2Buffer { size_t GetMemoryUsage() const; const struct v4l2_buffer& v4l2_buffer() const { return v4l2_buffer_; } const scoped_refptr& GetFrameResource(); + std::pair GetSavedmafd(); + std::pair GetSavedphys(); + std::pair Getg2dbufphys(); + std::pair Getg2dbufvirs(); + const struct v4l2_format& GetFmt() const {return format_;} private: V4L2Buffer(const IoctlAsCallback& ioctl_cb, @@ -203,6 +213,13 @@ class V4L2Buffer { const IoctlAsCallback ioctl_cb_; const MmapAsCallback mmap_cb_; std::vector plane_mappings_; + int dmafd0; + int dmafd1; + unsigned long phys_0; + unsigned long phys_1; + struct g2d_buf *g2dbuf_p0; + struct g2d_buf *g2dbuf_p1; + std::vector g2dbufs_fds; // V4L2 data as queried by QUERYBUF. struct v4l2_buffer v4l2_buffer_; @@ -257,6 +274,90 @@ V4L2Buffer::V4L2Buffer(const IoctlAsCallback& ioctl_cb, v4l2_buffer_.type = type; v4l2_buffer_.memory = memory; plane_mappings_.resize(V4L2_TYPE_IS_MULTIPLANAR(type) ? v4l2_buffer_.length : 1); + dmafd0 = dmafd1 = -1; + phys_0 = phys_1 = 0; + g2dbuf_p0 = g2dbuf_p1 = NULL; + + if (V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer_.type) && + format_.fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12M_8L128) { + VLOGF(3) << "Map physical address"; + + std::vector dmabuf_fds = GetDmabufsForV4L2Buffer( + ioctl_cb_, v4l2_buffer_.index, V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer_.type) ? v4l2_buffer_.length : 1, + static_cast(v4l2_buffer_.type)); + if (dmabuf_fds.empty()) { + LOG(ERROR) << "Failed to get DMABUFs of V4L2 buffer"; + return; + } + + // DMA buffer fds should not be invalid + for (const auto& dmabuf_fd : dmabuf_fds) { + if (!dmabuf_fd.is_valid()) { + LOG(ERROR) << "Fail to get DMABUFs of V4L2 buffer - invalid fd"; + return; + } + if(dmafd0 == -1) + dmafd0 = dmabuf_fd.get(); + else + dmafd1 = dmabuf_fd.get(); + } + + struct dma_buf_phys{ + unsigned long phys; + }; + #define DMA_BUF_IOCTL_PHYS _IOW(DMA_BUF_BASE, 10, struct dma_buf_phys) + struct dma_buf_phys query0, query1; + int ret = ioctl(dmafd0, DMA_BUF_IOCTL_PHYS, &query0); + if(ret != 0) { + LOG(ERROR)<< "DMA_BUF_IOCTL_PHYS failed at dmafd" << dmafd0; + return; + } + else { + phys_0 = query0.phys; + } + + ret = ioctl(dmafd1, DMA_BUF_IOCTL_PHYS, &query1); + if(ret != 0) { + LOG(ERROR)<< "DMA_BUF_IOCTL_PHYS failed at dmafd" << dmafd1; + return; + } + else { + phys_1 = query1.phys; + } + + if (g2d_alloc) { + g2dbuf_p0 = g2d_alloc(format_.fmt.pix_mp.width * format_.fmt.pix_mp.height, 0); + g2dbuf_p1 = g2d_alloc(format_.fmt.pix_mp.width * format_.fmt.pix_mp.height / 2, 0); + } + if((!g2dbuf_p0) || (!g2dbuf_p1)){ + LOG(ERROR)<<"g2d buf alloc failed"; + return; + } + + int tmpfd = -1; + if (g2d_buf_export_fd) + tmpfd = g2d_buf_export_fd(g2dbuf_p0); + tmpfd = dup(tmpfd); + if(tmpfd > 0) + g2dbufs_fds.push_back(base::ScopedFD(tmpfd)); + else if(tmpfd == -1) + { + LOG(ERROR) << "Failed duplicating g2d fd"; + return; + } + + if (g2d_buf_export_fd) + tmpfd = g2d_buf_export_fd(g2dbuf_p1); + tmpfd = dup(tmpfd); + if(tmpfd>0) + g2dbufs_fds.push_back(base::ScopedFD(tmpfd)); + else if(tmpfd == -1) + { + LOG(ERROR) << "Failed duplicating g2d fd"; + return; + } + + } } V4L2Buffer::~V4L2Buffer() { @@ -269,6 +370,32 @@ V4L2Buffer::~V4L2Buffer() { } } } + if(g2d_free && g2dbuf_p0 && g2dbuf_p1) { + g2d_free(g2dbuf_p0); + g2d_free(g2dbuf_p1); + } +} + +std::pair V4L2Buffer::GetSavedmafd() { + return std::make_pair(dmafd0, dmafd1); +} + +std::pair V4L2Buffer::GetSavedphys() { + return std::make_pair(phys_0, phys_1); +} + +std::pair V4L2Buffer::Getg2dbufphys() { + if(g2dbuf_p0 && g2dbuf_p1) + return std::make_pair(g2dbuf_p0->buf_paddr, g2dbuf_p1->buf_paddr); + else + return std::make_pair(-1, -1); +} + +std::pair V4L2Buffer::Getg2dbufvirs() { + if(g2dbuf_p0 && g2dbuf_p1) + return std::make_pair(g2dbuf_p0->buf_vaddr, g2dbuf_p1->buf_vaddr); + else + return std::make_pair(nullptr, nullptr); } bool V4L2Buffer::Query() { @@ -368,13 +495,18 @@ scoped_refptr V4L2Buffer::CreateFrame() { dmabuf_fds.emplace_back(duped_fd); } - if (V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer_.type)) + if (V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer_.type) && + format_.fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12M_8L128) { gfx::Size size(format_.fmt.pix_mp.width, format_.fmt.pix_mp.height); - else + return NativePixmapFrameResource::Create( + *layout, gfx::Rect(size), size, std::move(g2dbufs_fds), base::TimeDelta()); + } + else { gfx::Size size(format_.fmt.pix.width, format_.fmt.pix.height); - return NativePixmapFrameResource::Create( - *layout, gfx::Rect(size), size, std::move(dmabuf_fds), base::TimeDelta()); + return NativePixmapFrameResource::Create( + *layout, gfx::Rect(size), size, std::move(dmabuf_fds), base::TimeDelta()); + } } const scoped_refptr& V4L2Buffer::GetFrameResource() { @@ -1112,6 +1244,10 @@ V4L2Queue::V4L2Queue(const IoctlAsCallback& ioctl_cb, VPLOG_IF(4, supports_requests_) << "This queue does " << (supports_requests_ ? "" : "not") << " support requests."; + + g2d_handle = NULL; + if(g2d_open && g2d_open(&g2d_handle)) + VLOGF(1) << "g2d_open fail"; } V4L2Queue::~V4L2Queue() { @@ -1127,6 +1263,9 @@ V4L2Queue::~V4L2Queue() { VQLOGF(1) << "Failed to deallocate queue buffers"; } + if(g2d_close && g2d_handle) + g2d_close(g2d_handle); + std::move(destroy_cb_).Run(); } @@ -1170,6 +1309,8 @@ std::pair, int> V4L2Queue::GetFormat() { VPQLOGF(2) << "Failed to get format"; return std::make_pair(std::nullopt, errno); } + if (type_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + format.fmt.pix_mp.width = format.fmt.pix_mp.plane_fmt[0].bytesperline; return std::make_pair(format, 0); } @@ -1529,6 +1670,68 @@ std::pair V4L2Queue::DequeueBuffer() { } DCHECK(free_buffers_); + + if(type_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + buffers_[v4l2_buffer.index]->GetFmt().fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12M_8L128) + { + std::pair v4l_phys = buffers_[v4l2_buffer.index]->GetSavedphys(); + int width = buffers_[v4l2_buffer.index]->GetFmt().fmt.pix_mp.width; + int height = buffers_[v4l2_buffer.index]->GetFmt().fmt.pix_mp.height; + int stride = buffers_[v4l2_buffer.index]->GetFmt().fmt.pix_mp.plane_fmt[0].bytesperline; + bool interlaced = false; + switch (buffers_[v4l2_buffer.index]->GetFmt().fmt.pix_mp.field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_SEQ_TB: + interlaced = true; + break; + default: + break; + }; + struct g2d_surfaceEx srcEx, dstEx; + struct g2d_surface *src = &srcEx.base; + struct g2d_surface *dst = &dstEx.base; + + dst->format = G2D_NV12; + dst->planes[0] = buffers_[v4l2_buffer.index]->Getg2dbufphys().first; + dst->planes[1] = buffers_[v4l2_buffer.index]->Getg2dbufphys().second; + dstEx.tiling = G2D_LINEAR; + dst->left = 0; + dst->top = 0; + dst->right = dst->left + width; + dst->bottom = dst->top + height; + dst->stride= width; + dst->width = width; + dst->height = height; + dst->rot = G2D_ROTATION_0; + dst->global_alpha = 0xff; + dst->blendfunc = G2D_ONE_MINUS_SRC_ALPHA; + dst->clrcolor = 0; + + src->format = G2D_NV12; + src->planes[0] = v4l_phys.first; + src->planes[1] = v4l_phys.second; + srcEx.tiling = G2D_AMPHION_TILED; + if (interlaced) { + srcEx.tiling = static_cast(0x18); //G2D_AMPHION_TILED | G2D_AMPHION_INTERLACED; + DVLOGF(4)<<"interlaced video convert"; + } + src->left = 0; + src->top = 0; + src->right = src->left + width; + src->bottom = src->top + height; + src->stride= stride; + src->width = width; + src->height = height; + src->rot = G2D_ROTATION_0; + src->global_alpha = 0xff; + src->blendfunc = G2D_ONE; + + if (g2d_blitEx) + g2d_blitEx(g2d_handle, &srcEx, &dstEx); + } + return std::make_pair(true, V4L2BufferRefFactory::CreateReadableRef( v4l2_buffer, weak_this_factory_.GetWeakPtr(), std::move(queued_frame))); diff --git a/media/gpu/v4l2/v4l2_queue.h b/media/gpu/v4l2/v4l2_queue.h index 85c7920417935..1cc22fff58277 100644 --- a/media/gpu/v4l2/v4l2_queue.h +++ b/media/gpu/v4l2/v4l2_queue.h @@ -584,6 +584,7 @@ class MEDIA_GPU_EXPORT V4L2Queue std::optional current_format_; std::vector> buffers_; + void* g2d_handle; // Buffers that are available for client to get and submit. // Buffers in this list are not referenced by anyone else than ourselves. -- 2.34.1