/* * Copyright (C) 2005-2020 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "VideoBufferDMA.h" #include "ServiceBroker.h" #include "utils/BufferObject.h" #include "utils/DRMHelpers.h" #include "utils/log.h" extern "C" { #include #include } CVideoBufferDMA::CVideoBufferDMA(IVideoBufferPool& pool, int id, uint32_t fourcc, uint64_t size) : CVideoBufferDRMPRIMEFFmpeg(pool, id), m_bo(CBufferObject::GetBufferObject(true)), m_fourcc(fourcc), m_size(size) { } CVideoBufferDMA::~CVideoBufferDMA() { Destroy(); } AVDRMFrameDescriptor* CVideoBufferDMA::GetDescriptor() const { return const_cast(&m_descriptor); } uint8_t* CVideoBufferDMA::GetMemPtr() { return m_addr; } void CVideoBufferDMA::GetPlanes(uint8_t* (&planes)[YuvImage::MAX_PLANES]) { for (uint32_t i = 0; i < YuvImage::MAX_PLANES; i++) planes[i] = m_addr + m_offsets[i]; } void CVideoBufferDMA::GetStrides(int (&strides)[YuvImage::MAX_PLANES]) { for (uint32_t i = 0; i < YuvImage::MAX_PLANES; i++) strides[i] = m_strides[i]; } void CVideoBufferDMA::SetDimensions(int width, int height) { SetDimensions(width, height, m_strides, m_offsets); } void CVideoBufferDMA::SetDimensions(int width, int height, const int (&strides)[YuvImage::MAX_PLANES]) { SetDimensions(width, height, strides, m_offsets); } void CVideoBufferDMA::SetDimensions(int width, int height, const int (&strides)[YuvImage::MAX_PLANES], const int (&planeOffsets)[YuvImage::MAX_PLANES]) { m_width = width; m_height = height; AVDRMFrameDescriptor* descriptor = &m_descriptor; descriptor->nb_objects = 1; descriptor->objects[0].fd = m_fd; descriptor->nb_layers = 1; AVDRMLayerDescriptor* layer = &descriptor->layers[0]; layer->format = m_fourcc; layer->nb_planes = m_planes; for (uint32_t i = 0; i < m_planes; i++) { layer->planes[i].offset = planeOffsets[i]; layer->planes[i].pitch = strides[i]; } if (CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO)) { std::string planeStr; for (uint32_t plane = 0; plane < m_planes; plane++) planeStr.append(fmt::format("\nplane[{}]: stride={}\toffset={}", plane, strides[plane], planeOffsets[plane])); CLog::Log(LOGDEBUG, LOGVIDEO, "CVideoBufferDMA::{} - frame layout id={} fourcc={}{}", __FUNCTION__, m_id, DRMHELPERS::FourCCToString(m_fourcc), planeStr); } } bool CVideoBufferDMA::Alloc() { if (!m_bo->CreateBufferObject(m_size)) return false; m_fd = m_bo->GetFd(); m_addr = m_bo->GetMemory(); m_planes = 3; // CAddonVideoCodec only requests AV_PIX_FMT_YUV420P for now CLog::Log(LOGDEBUG, LOGVIDEO, "CVideoBufferDMA::{} - id={} fourcc={} fd={} size={} addr={}", __FUNCTION__, m_id, DRMHELPERS::FourCCToString(m_fourcc), m_fd, m_size, fmt::ptr(m_addr)); return true; } void CVideoBufferDMA::Export(AVFrame* frame, uint32_t width, uint32_t height) { m_planes = av_pix_fmt_count_planes(static_cast(frame->format)); if (m_planes < 2) throw std::runtime_error( "non-planar formats not supported: " + std::string(av_get_pix_fmt_name(static_cast(frame->format)))); for (uint32_t plane = 0; plane < m_planes; plane++) { m_strides[plane] = av_image_get_linesize(static_cast(frame->format), width, plane); m_offsets[plane] = plane == 0 ? 0 : (m_offsets[plane - 1] + m_strides[plane - 1] * (height >> (plane - 1))); } if (CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO)) { std::string planeStr; for (uint32_t plane = 0; plane < m_planes; plane++) planeStr.append(fmt::format("\nplane[{}]: stride={}\toffset={}", plane, m_strides[plane], m_offsets[plane])); CLog::Log(LOGDEBUG, LOGVIDEO, "CVideoBufferDMA::{} - frame layout id={} fourcc={}{}", __FUNCTION__, m_id, DRMHELPERS::FourCCToString(m_fourcc), planeStr); } for (uint32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) { frame->data[i] = i < m_planes ? m_addr + m_offsets[i] : nullptr; frame->linesize[i] = i < m_planes ? m_strides[i] : 0; frame->buf[i] = i == 0 ? frame->opaque_ref : nullptr; } frame->extended_data = frame->data; frame->opaque_ref = nullptr; } void CVideoBufferDMA::SyncStart() { m_bo->SyncStart(); } void CVideoBufferDMA::SyncEnd() { m_bo->SyncEnd(); } void CVideoBufferDMA::Destroy() { m_bo->ReleaseMemory(); m_bo->DestroyBufferObject(); for (auto& offset : m_offsets) offset = 0; for (auto& stride : m_strides) stride = 0; m_planes = 0; m_width = 0; m_height = 0; m_fourcc = 0; m_size = 0; m_addr = nullptr; m_fd = -1; }