mirror of
https://github.com/nyanmisaka/ffmpeg-rockchip.git
synced 2026-01-24 02:20:56 +01:00
lavu: add RKMPP hwcontext
Signed-off-by: nyanmisaka <nst799610810@gmail.com> Co-authored-by: boogie <boogiepop@gmx.com>
This commit is contained in:
parent
af3862741a
commit
8f1637be7f
7 changed files with 767 additions and 3 deletions
6
configure
vendored
6
configure
vendored
|
|
@ -3991,7 +3991,7 @@ avfilter_deps="avutil"
|
|||
avfilter_suggest="libm stdatomic"
|
||||
avformat_deps="avcodec avutil"
|
||||
avformat_suggest="libm network zlib stdatomic"
|
||||
avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic"
|
||||
avutil_suggest="clock_gettime ffnvcodec gcrypt libm libdrm libmfx opencl openssl rkmpp user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic"
|
||||
postproc_deps="avutil gpl"
|
||||
postproc_suggest="libm stdatomic"
|
||||
swresample_deps="avutil"
|
||||
|
|
@ -7084,8 +7084,8 @@ enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" ope
|
|||
check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
|
||||
die "ERROR: openssl not found"; }
|
||||
enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init
|
||||
enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create &&
|
||||
require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create &&
|
||||
enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create &&
|
||||
require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.9" rockchip/rk_mpi.h mpp_create &&
|
||||
{ enabled libdrm ||
|
||||
die "ERROR: rkmpp requires --enable-libdrm"; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ HEADERS = adler32.h \
|
|||
hwcontext_videotoolbox.h \
|
||||
hwcontext_vdpau.h \
|
||||
hwcontext_vulkan.h \
|
||||
hwcontext_rkmpp.h \
|
||||
iamf.h \
|
||||
imgutils.h \
|
||||
intfloat.h \
|
||||
|
|
@ -205,6 +206,7 @@ OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o
|
|||
OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o
|
||||
OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o
|
||||
OBJS-$(CONFIG_VULKAN) += hwcontext_vulkan.o vulkan.o
|
||||
OBJS-$(CONFIG_RKMPP) += hwcontext_rkmpp.o
|
||||
|
||||
OBJS-$(!CONFIG_VULKAN) += hwcontext_stub.o
|
||||
|
||||
|
|
@ -228,6 +230,7 @@ SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h
|
|||
SKIPHEADERS-$(CONFIG_VULKAN) += hwcontext_vulkan.h vulkan.h \
|
||||
vulkan_functions.h \
|
||||
vulkan_loader.h
|
||||
SKIPHEADERS-$(CONFIG_RKMPP) += hwcontext_rkmpp.h
|
||||
|
||||
TESTPROGS = adler32 \
|
||||
aes \
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ static const HWContextType * const hw_table[] = {
|
|||
#endif
|
||||
#if CONFIG_VULKAN
|
||||
&ff_hwcontext_type_vulkan,
|
||||
#endif
|
||||
#if CONFIG_RKMPP
|
||||
&ff_hwcontext_type_rkmpp,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
|
@ -82,6 +85,7 @@ static const char *const hw_type_names[] = {
|
|||
[AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
|
||||
[AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
|
||||
[AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
|
||||
[AV_HWDEVICE_TYPE_RKMPP] = "rkmpp",
|
||||
};
|
||||
|
||||
typedef struct FFHWDeviceContext {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ enum AVHWDeviceType {
|
|||
AV_HWDEVICE_TYPE_MEDIACODEC,
|
||||
AV_HWDEVICE_TYPE_VULKAN,
|
||||
AV_HWDEVICE_TYPE_D3D12VA,
|
||||
AV_HWDEVICE_TYPE_RKMPP,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -163,5 +163,6 @@ extern const HWContextType ff_hwcontext_type_vdpau;
|
|||
extern const HWContextType ff_hwcontext_type_videotoolbox;
|
||||
extern const HWContextType ff_hwcontext_type_mediacodec;
|
||||
extern const HWContextType ff_hwcontext_type_vulkan;
|
||||
extern const HWContextType ff_hwcontext_type_rkmpp;
|
||||
|
||||
#endif /* AVUTIL_HWCONTEXT_INTERNAL_H */
|
||||
|
|
|
|||
602
libavutil/hwcontext_rkmpp.c
Normal file
602
libavutil/hwcontext_rkmpp.c
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* This was introduced in version 4.6. And may not exist all without an
|
||||
* optional package. So to prevent a hard dependency on needing the Linux
|
||||
* kernel headers to compile, make this optional. */
|
||||
#if HAVE_LINUX_DMA_BUF_H
|
||||
#include <linux/dma-buf.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "avassert.h"
|
||||
#include "hwcontext.h"
|
||||
#include "hwcontext_rkmpp.h"
|
||||
#include "hwcontext_internal.h"
|
||||
#include "imgutils.h"
|
||||
|
||||
static const struct {
|
||||
enum AVPixelFormat pixfmt;
|
||||
uint32_t drm_format;
|
||||
} supported_formats[] = {
|
||||
/* grayscale */
|
||||
{ AV_PIX_FMT_GRAY8, DRM_FORMAT_R8, },
|
||||
/* fully-planar YUV */
|
||||
{ AV_PIX_FMT_YUV420P, DRM_FORMAT_YUV420, },
|
||||
{ AV_PIX_FMT_YUVJ420P, DRM_FORMAT_YUV420, },
|
||||
{ AV_PIX_FMT_YUV422P, DRM_FORMAT_YUV422, },
|
||||
{ AV_PIX_FMT_YUVJ422P, DRM_FORMAT_YUV422, },
|
||||
{ AV_PIX_FMT_YUV444P, DRM_FORMAT_YUV444, },
|
||||
{ AV_PIX_FMT_YUVJ444P, DRM_FORMAT_YUV444, },
|
||||
/* semi-planar YUV */
|
||||
{ AV_PIX_FMT_NV12, DRM_FORMAT_NV12, },
|
||||
{ AV_PIX_FMT_NV21, DRM_FORMAT_NV21, },
|
||||
{ AV_PIX_FMT_NV16, DRM_FORMAT_NV16, },
|
||||
{ AV_PIX_FMT_NV24, DRM_FORMAT_NV24, },
|
||||
{ AV_PIX_FMT_NV42, DRM_FORMAT_NV42, },
|
||||
/* semi-planar YUV 10-bit */
|
||||
{ AV_PIX_FMT_P010, DRM_FORMAT_P010, },
|
||||
{ AV_PIX_FMT_P210, DRM_FORMAT_P210, },
|
||||
{ AV_PIX_FMT_NV15, DRM_FORMAT_NV15, },
|
||||
{ AV_PIX_FMT_NV20, DRM_FORMAT_NV20, },
|
||||
/* packed YUV */
|
||||
{ AV_PIX_FMT_YUYV422, DRM_FORMAT_YUYV, },
|
||||
{ AV_PIX_FMT_YVYU422, DRM_FORMAT_YVYU, },
|
||||
{ AV_PIX_FMT_UYVY422, DRM_FORMAT_UYVY, },
|
||||
/* packed RGB */
|
||||
{ AV_PIX_FMT_RGB444LE, DRM_FORMAT_XRGB4444, },
|
||||
{ AV_PIX_FMT_RGB444BE, DRM_FORMAT_XRGB4444 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_BGR444LE, DRM_FORMAT_XBGR4444, },
|
||||
{ AV_PIX_FMT_BGR444BE, DRM_FORMAT_XBGR4444 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_RGB555LE, DRM_FORMAT_XRGB1555, },
|
||||
{ AV_PIX_FMT_RGB555BE, DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_BGR555LE, DRM_FORMAT_XBGR1555, },
|
||||
{ AV_PIX_FMT_BGR555BE, DRM_FORMAT_XBGR1555 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_RGB565LE, DRM_FORMAT_RGB565, },
|
||||
{ AV_PIX_FMT_RGB565BE, DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_BGR565LE, DRM_FORMAT_BGR565, },
|
||||
{ AV_PIX_FMT_BGR565BE, DRM_FORMAT_BGR565 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_RGB24, DRM_FORMAT_RGB888, },
|
||||
{ AV_PIX_FMT_BGR24, DRM_FORMAT_BGR888, },
|
||||
{ AV_PIX_FMT_RGBA, DRM_FORMAT_ABGR8888, },
|
||||
{ AV_PIX_FMT_RGB0, DRM_FORMAT_XBGR8888, },
|
||||
{ AV_PIX_FMT_BGRA, DRM_FORMAT_ARGB8888, },
|
||||
{ AV_PIX_FMT_BGR0, DRM_FORMAT_XRGB8888, },
|
||||
{ AV_PIX_FMT_ARGB, DRM_FORMAT_BGRA8888, },
|
||||
{ AV_PIX_FMT_0RGB, DRM_FORMAT_BGRX8888, },
|
||||
{ AV_PIX_FMT_ABGR, DRM_FORMAT_RGBA8888, },
|
||||
{ AV_PIX_FMT_0BGR, DRM_FORMAT_RGBX8888, },
|
||||
{ AV_PIX_FMT_X2RGB10LE, DRM_FORMAT_XRGB2101010, },
|
||||
{ AV_PIX_FMT_X2RGB10BE, DRM_FORMAT_XRGB2101010 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
{ AV_PIX_FMT_X2BGR10LE, DRM_FORMAT_XBGR2101010, },
|
||||
{ AV_PIX_FMT_X2BGR10BE, DRM_FORMAT_XBGR2101010 | DRM_FORMAT_BIG_ENDIAN, },
|
||||
};
|
||||
|
||||
static int rkmpp_device_create(AVHWDeviceContext *hwdev, const char *device,
|
||||
AVDictionary *opts, int flags)
|
||||
{
|
||||
AVRKMPPDeviceContext *hwctx = hwdev->hwctx;
|
||||
AVDictionaryEntry *opt_d = NULL;
|
||||
|
||||
hwctx->flags = MPP_BUFFER_FLAGS_DMA32;
|
||||
|
||||
opt_d = av_dict_get(opts, "dma32", NULL, 0);
|
||||
if (opt_d && !strtol(opt_d->value, NULL, 10))
|
||||
hwctx->flags &= ~MPP_BUFFER_FLAGS_DMA32;
|
||||
|
||||
opt_d = av_dict_get(opts, "cacheable", NULL, 0);
|
||||
if (opt_d && strtol(opt_d->value, NULL, 10))
|
||||
hwctx->flags |= MPP_BUFFER_FLAGS_CACHABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkmpp_frames_get_constraints(AVHWDeviceContext *hwdev,
|
||||
const void *hwconfig,
|
||||
AVHWFramesConstraints *constraints)
|
||||
{
|
||||
int i;
|
||||
|
||||
constraints->min_width = 16;
|
||||
constraints->min_height = 16;
|
||||
|
||||
constraints->valid_hw_formats =
|
||||
av_malloc_array(2, sizeof(enum AVPixelFormat));
|
||||
if (!constraints->valid_hw_formats)
|
||||
return AVERROR(ENOMEM);
|
||||
constraints->valid_hw_formats[0] = AV_PIX_FMT_DRM_PRIME;
|
||||
constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
|
||||
|
||||
constraints->valid_sw_formats =
|
||||
av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1,
|
||||
sizeof(enum AVPixelFormat));
|
||||
if (!constraints->valid_sw_formats)
|
||||
return AVERROR(ENOMEM);
|
||||
for(i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
|
||||
constraints->valid_sw_formats[i] = supported_formats[i].pixfmt;
|
||||
constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rkmpp_free_drm_frame_descriptor(void *opaque, uint8_t *data)
|
||||
{
|
||||
|
||||
MppBuffer mpp_buf = opaque;
|
||||
AVRKMPPDRMFrameDescriptor *desc = (AVRKMPPDRMFrameDescriptor *)data;
|
||||
int ret;
|
||||
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
if (mpp_buf) {
|
||||
ret = mpp_buffer_put(mpp_buf);
|
||||
if (ret != MPP_OK)
|
||||
av_log(NULL, AV_LOG_WARNING,
|
||||
"Failed to put MPP buffer: %d\n", ret);
|
||||
}
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
av_free(desc);
|
||||
}
|
||||
|
||||
static int rkmpp_get_aligned_linesize(enum AVPixelFormat pix_fmt, int width, int plane)
|
||||
{
|
||||
const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(pix_fmt);
|
||||
const int is_rgb = pixdesc->flags & AV_PIX_FMT_FLAG_RGB;
|
||||
const int is_yuv = !is_rgb && pixdesc->nb_components >= 2;
|
||||
const int is_planar = pixdesc->flags & AV_PIX_FMT_FLAG_PLANAR;
|
||||
const int is_packed_fmt = is_rgb || (!is_rgb && !is_planar);
|
||||
const int is_fully_planar = is_planar &&
|
||||
pixdesc->comp[1].plane != pixdesc->comp[2].plane;
|
||||
int linesize;
|
||||
|
||||
if (pix_fmt == AV_PIX_FMT_NV15 ||
|
||||
pix_fmt == AV_PIX_FMT_NV20) {
|
||||
const int width_align_256_odds = FFALIGN(width, 256) | 256;
|
||||
return FFALIGN(width_align_256_odds * 10 / 8, 64);
|
||||
}
|
||||
|
||||
linesize = av_image_get_linesize(pix_fmt, width, plane);
|
||||
|
||||
if (is_packed_fmt) {
|
||||
const int pixel_width = av_get_padded_bits_per_pixel(pixdesc) / 8;
|
||||
linesize = FFALIGN(linesize / pixel_width, 16) * pixel_width;
|
||||
} else if (is_yuv && is_fully_planar) {
|
||||
linesize = FFALIGN(linesize, 16 >> (plane ? pixdesc->log2_chroma_w : 0));
|
||||
} else
|
||||
linesize = FFALIGN(linesize, 64);
|
||||
|
||||
return linesize;
|
||||
}
|
||||
|
||||
static AVBufferRef *rkmpp_drm_pool_alloc(void *opaque, size_t size)
|
||||
{
|
||||
int ret;
|
||||
AVHWFramesContext *hwfc = opaque;
|
||||
AVRKMPPFramesContext *avfc = hwfc->hwctx;
|
||||
AVRKMPPDeviceContext *hwctx = hwfc->device_ctx->hwctx;
|
||||
AVRKMPPDRMFrameDescriptor *desc;
|
||||
AVDRMLayerDescriptor *layer;
|
||||
AVBufferRef *ref;
|
||||
|
||||
int i;
|
||||
const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(hwfc->sw_format);
|
||||
const int bits_pp = av_get_padded_bits_per_pixel(pixdesc);
|
||||
const int aligned_w = FFALIGN(hwfc->width * 5 / 4, 64);
|
||||
const int aligned_h = FFALIGN(hwfc->height * 5 / 4, 64);
|
||||
|
||||
MppBuffer mpp_buf = NULL;
|
||||
size_t mpp_buf_size = aligned_w * aligned_h * bits_pp / 8;
|
||||
|
||||
if (hwfc->initial_pool_size > 0 &&
|
||||
avfc->nb_frames >= hwfc->initial_pool_size)
|
||||
return NULL;
|
||||
|
||||
desc = av_mallocz(sizeof(*desc));
|
||||
if (!desc)
|
||||
return NULL;
|
||||
|
||||
desc->drm_desc.nb_objects = 1;
|
||||
desc->drm_desc.nb_layers = 1;
|
||||
|
||||
ret = mpp_buffer_get(avfc->buf_group, &mpp_buf, mpp_buf_size);
|
||||
if (ret != MPP_OK || !mpp_buf) {
|
||||
av_log(hwctx, AV_LOG_ERROR, "Failed to get MPP buffer: %d\n", ret);
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
desc->buffers[0] = mpp_buf;
|
||||
|
||||
desc->drm_desc.objects[0].fd = mpp_buffer_get_fd(mpp_buf);
|
||||
desc->drm_desc.objects[0].size = mpp_buffer_get_size(mpp_buf);
|
||||
|
||||
layer = &desc->drm_desc.layers[0];
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
|
||||
if (supported_formats[i].pixfmt == hwfc->sw_format) {
|
||||
layer->format = supported_formats[i].drm_format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
layer->nb_planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
||||
layer->planes[0].object_index = 0;
|
||||
layer->planes[0].offset = 0;
|
||||
layer->planes[0].pitch =
|
||||
rkmpp_get_aligned_linesize(hwfc->sw_format, hwfc->width, 0);
|
||||
|
||||
for (i = 1; i < layer->nb_planes; i++) {
|
||||
layer->planes[i].object_index = 0;
|
||||
layer->planes[i].offset =
|
||||
layer->planes[i-1].offset +
|
||||
layer->planes[i-1].pitch * (FFALIGN(hwfc->height, 2) >> (i > 1 ? pixdesc->log2_chroma_h : 0));
|
||||
layer->planes[i].pitch =
|
||||
rkmpp_get_aligned_linesize(hwfc->sw_format, hwfc->width, i);
|
||||
}
|
||||
|
||||
ref = av_buffer_create((uint8_t*)desc, sizeof(*desc), rkmpp_free_drm_frame_descriptor,
|
||||
mpp_buf, 0);
|
||||
if (!ref) {
|
||||
av_log(hwfc, AV_LOG_ERROR, "Failed to create RKMPP buffer.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hwfc->initial_pool_size > 0) {
|
||||
av_assert0(avfc->nb_frames < hwfc->initial_pool_size);
|
||||
memcpy(&avfc->frames[avfc->nb_frames], desc, sizeof(*desc));
|
||||
++avfc->nb_frames;
|
||||
}
|
||||
|
||||
return ref;
|
||||
|
||||
fail:
|
||||
rkmpp_free_drm_frame_descriptor(mpp_buf, (uint8_t *)desc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rkmpp_frames_init(AVHWFramesContext *hwfc)
|
||||
{
|
||||
AVRKMPPFramesContext *avfc = hwfc->hwctx;
|
||||
AVRKMPPDeviceContext *hwctx = hwfc->device_ctx->hwctx;
|
||||
int i, ret;
|
||||
|
||||
if (hwfc->pool)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
|
||||
if (supported_formats[i].pixfmt == hwfc->sw_format)
|
||||
break;
|
||||
if (i >= FF_ARRAY_ELEMS(supported_formats)) {
|
||||
av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
|
||||
av_get_pix_fmt_name(hwfc->sw_format));
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
avfc->nb_frames = 0;
|
||||
avfc->frames = NULL;
|
||||
if (hwfc->initial_pool_size > 0) {
|
||||
avfc->frames = av_malloc(hwfc->initial_pool_size *
|
||||
sizeof(*avfc->frames));
|
||||
if (!avfc->frames)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
ret = mpp_buffer_group_get_internal(&avfc->buf_group,
|
||||
MPP_BUFFER_TYPE_DRM | hwctx->flags | avfc->flags);
|
||||
if (ret != MPP_OK) {
|
||||
av_log(hwfc, AV_LOG_ERROR, "Failed to get MPP internal buffer group: %d\n", ret);
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
ffhwframesctx(hwfc)->pool_internal =
|
||||
av_buffer_pool_init2(sizeof(AVRKMPPDRMFrameDescriptor), hwfc,
|
||||
rkmpp_drm_pool_alloc, NULL);
|
||||
if (!ffhwframesctx(hwfc)->pool_internal) {
|
||||
av_log(hwfc, AV_LOG_ERROR, "Failed to create RKMPP buffer pool.\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rkmpp_frames_uninit(AVHWFramesContext *hwfc)
|
||||
{
|
||||
AVRKMPPFramesContext *avfc = hwfc->hwctx;
|
||||
|
||||
av_freep(&avfc->frames);
|
||||
|
||||
if (avfc->buf_group) {
|
||||
mpp_buffer_group_put(avfc->buf_group);
|
||||
avfc->buf_group = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rkmpp_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
|
||||
{
|
||||
frame->buf[0] = av_buffer_pool_get(hwfc->pool);
|
||||
if (!frame->buf[0])
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
frame->data[0] = (uint8_t*)frame->buf[0]->data;
|
||||
|
||||
frame->format = AV_PIX_FMT_DRM_PRIME;
|
||||
frame->width = hwfc->width;
|
||||
frame->height = hwfc->height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct RKMPPDRMMapping {
|
||||
// Address and length of each mmap()ed region.
|
||||
int nb_regions;
|
||||
int sync_flags;
|
||||
int object[AV_DRM_MAX_PLANES];
|
||||
void *address[AV_DRM_MAX_PLANES];
|
||||
size_t length[AV_DRM_MAX_PLANES];
|
||||
int unmap[AV_DRM_MAX_PLANES];
|
||||
} RKMPPDRMMapping;
|
||||
|
||||
static void rkmpp_unmap_frame(AVHWFramesContext *hwfc,
|
||||
HWMapDescriptor *hwmap)
|
||||
{
|
||||
AVRKMPPFramesContext *avfc = hwfc->hwctx;
|
||||
RKMPPDRMMapping *map = hwmap->priv;
|
||||
|
||||
for (int i = 0; i < map->nb_regions; i++) {
|
||||
#if HAVE_LINUX_DMA_BUF_H
|
||||
struct dma_buf_sync sync = { .flags = DMA_BUF_SYNC_END | map->sync_flags };
|
||||
if (avfc->flags & MPP_BUFFER_FLAGS_CACHABLE)
|
||||
ioctl(map->object[i], DMA_BUF_IOCTL_SYNC, &sync);
|
||||
#endif
|
||||
if (map->address[i] && map->unmap[i])
|
||||
munmap(map->address[i], map->length[i]);
|
||||
}
|
||||
|
||||
av_free(map);
|
||||
}
|
||||
|
||||
static int rkmpp_map_frame(AVHWFramesContext *hwfc,
|
||||
AVFrame *dst, const AVFrame *src, int flags)
|
||||
{
|
||||
AVRKMPPFramesContext *avfc = hwfc->hwctx;
|
||||
const AVRKMPPDRMFrameDescriptor *desc = (AVRKMPPDRMFrameDescriptor *)src->data[0];
|
||||
#if HAVE_LINUX_DMA_BUF_H
|
||||
struct dma_buf_sync sync_start = { 0 };
|
||||
#endif
|
||||
RKMPPDRMMapping *map;
|
||||
int err, i, p, plane;
|
||||
int mmap_prot;
|
||||
void *addr;
|
||||
|
||||
map = av_mallocz(sizeof(*map));
|
||||
if (!map)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
mmap_prot = 0;
|
||||
if (flags & AV_HWFRAME_MAP_READ)
|
||||
mmap_prot |= PROT_READ;
|
||||
if (flags & AV_HWFRAME_MAP_WRITE)
|
||||
mmap_prot |= PROT_WRITE;
|
||||
|
||||
#if HAVE_LINUX_DMA_BUF_H
|
||||
if (flags & AV_HWFRAME_MAP_READ)
|
||||
map->sync_flags |= DMA_BUF_SYNC_READ;
|
||||
if (flags & AV_HWFRAME_MAP_WRITE)
|
||||
map->sync_flags |= DMA_BUF_SYNC_WRITE;
|
||||
sync_start.flags = DMA_BUF_SYNC_START | map->sync_flags;
|
||||
#endif
|
||||
|
||||
if (desc->drm_desc.objects[0].format_modifier != DRM_FORMAT_MOD_LINEAR) {
|
||||
av_log(hwfc, AV_LOG_ERROR, "Transfer non-linear DRM_PRIME frame is not supported!\n");
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
|
||||
av_assert0(desc->drm_desc.nb_objects <= AV_DRM_MAX_PLANES);
|
||||
for (i = 0; i < desc->drm_desc.nb_objects; i++) {
|
||||
addr = NULL;
|
||||
if (desc->buffers[i])
|
||||
addr = mpp_buffer_get_ptr(desc->buffers[i]);
|
||||
|
||||
if (addr) {
|
||||
map->unmap[i] = 0;
|
||||
} else {
|
||||
addr = mmap(NULL, desc->drm_desc.objects[i].size, mmap_prot, MAP_SHARED,
|
||||
desc->drm_desc.objects[i].fd, 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
err = AVERROR(errno);
|
||||
av_log(hwfc, AV_LOG_ERROR, "Failed to map RKMPP object %d to "
|
||||
"memory: %d.\n", desc->drm_desc.objects[i].fd, errno);
|
||||
goto fail;
|
||||
}
|
||||
map->unmap[i] = 1;
|
||||
}
|
||||
|
||||
map->address[i] = addr;
|
||||
map->length[i] = desc->drm_desc.objects[i].size;
|
||||
map->object[i] = desc->drm_desc.objects[i].fd;
|
||||
|
||||
#if HAVE_LINUX_DMA_BUF_H
|
||||
/* We're not checking for errors here because the kernel may not
|
||||
* support the ioctl, in which case its okay to carry on */
|
||||
if (avfc->flags & MPP_BUFFER_FLAGS_CACHABLE)
|
||||
ioctl(desc->drm_desc.objects[i].fd, DMA_BUF_IOCTL_SYNC, &sync_start);
|
||||
#endif
|
||||
}
|
||||
map->nb_regions = i;
|
||||
|
||||
plane = 0;
|
||||
for (i = 0; i < desc->drm_desc.nb_layers; i++) {
|
||||
const AVDRMLayerDescriptor *layer = &desc->drm_desc.layers[i];
|
||||
for (p = 0; p < layer->nb_planes; p++) {
|
||||
dst->data[plane] =
|
||||
(uint8_t*)map->address[layer->planes[p].object_index] +
|
||||
layer->planes[p].offset;
|
||||
dst->linesize[plane] = layer->planes[p].pitch;
|
||||
++plane;
|
||||
}
|
||||
}
|
||||
av_assert0(plane <= AV_DRM_MAX_PLANES);
|
||||
|
||||
dst->width = src->width;
|
||||
dst->height = src->height;
|
||||
|
||||
err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
|
||||
&rkmpp_unmap_frame, map);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < desc->drm_desc.nb_objects; i++) {
|
||||
if (map->address[i] && map->unmap[i])
|
||||
munmap(map->address[i], map->length[i]);
|
||||
}
|
||||
av_free(map);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rkmpp_transfer_get_formats(AVHWFramesContext *ctx,
|
||||
enum AVHWFrameTransferDirection dir,
|
||||
enum AVPixelFormat **formats)
|
||||
{
|
||||
enum AVPixelFormat *pix_fmts;
|
||||
|
||||
pix_fmts = av_malloc_array(2, sizeof(*pix_fmts));
|
||||
if (!pix_fmts)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
pix_fmts[0] = ctx->sw_format;
|
||||
pix_fmts[1] = AV_PIX_FMT_NONE;
|
||||
|
||||
*formats = pix_fmts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkmpp_transfer_data_from(AVHWFramesContext *hwfc,
|
||||
AVFrame *dst, const AVFrame *src)
|
||||
{
|
||||
AVFrame *map;
|
||||
int err;
|
||||
|
||||
if (dst->width > hwfc->width || dst->height > hwfc->height)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
map = av_frame_alloc();
|
||||
if (!map)
|
||||
return AVERROR(ENOMEM);
|
||||
map->format = dst->format;
|
||||
|
||||
err = rkmpp_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
map->width = dst->width;
|
||||
map->height = dst->height;
|
||||
|
||||
err = av_frame_copy(dst, map);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = 0;
|
||||
fail:
|
||||
av_frame_free(&map);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rkmpp_transfer_data_to(AVHWFramesContext *hwfc,
|
||||
AVFrame *dst, const AVFrame *src)
|
||||
{
|
||||
AVFrame *map;
|
||||
int err;
|
||||
|
||||
if (src->width > hwfc->width || src->height > hwfc->height)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
map = av_frame_alloc();
|
||||
if (!map)
|
||||
return AVERROR(ENOMEM);
|
||||
map->format = src->format;
|
||||
|
||||
err = rkmpp_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE |
|
||||
AV_HWFRAME_MAP_OVERWRITE);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
map->width = src->width;
|
||||
map->height = src->height;
|
||||
|
||||
err = av_frame_copy(map, src);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = 0;
|
||||
fail:
|
||||
av_frame_free(&map);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rkmpp_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
|
||||
const AVFrame *src, int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (hwfc->sw_format != dst->format)
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
err = rkmpp_map_frame(hwfc, dst, src, flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = av_frame_copy_props(dst, src);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const HWContextType ff_hwcontext_type_rkmpp = {
|
||||
.type = AV_HWDEVICE_TYPE_RKMPP,
|
||||
.name = "RKMPP",
|
||||
|
||||
.device_hwctx_size = sizeof(AVRKMPPDeviceContext),
|
||||
.frames_hwctx_size = sizeof(AVRKMPPFramesContext),
|
||||
|
||||
.device_create = &rkmpp_device_create,
|
||||
|
||||
.frames_get_constraints = &rkmpp_frames_get_constraints,
|
||||
|
||||
.frames_get_buffer = &rkmpp_get_buffer,
|
||||
.frames_init = &rkmpp_frames_init,
|
||||
.frames_uninit = &rkmpp_frames_uninit,
|
||||
.transfer_get_formats = &rkmpp_transfer_get_formats,
|
||||
.transfer_data_to = &rkmpp_transfer_data_to,
|
||||
.transfer_data_from = &rkmpp_transfer_data_from,
|
||||
.map_from = &rkmpp_map_from,
|
||||
|
||||
.pix_fmts = (const enum AVPixelFormat[]) {
|
||||
AV_PIX_FMT_DRM_PRIME,
|
||||
AV_PIX_FMT_NONE
|
||||
},
|
||||
};
|
||||
153
libavutil/hwcontext_rkmpp.h
Normal file
153
libavutil/hwcontext_rkmpp.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_HWCONTEXT_RKMPP_H
|
||||
#define AVUTIL_HWCONTEXT_RKMPP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <rockchip/rk_mpi.h>
|
||||
|
||||
#include "hwcontext_drm.h"
|
||||
|
||||
#ifndef DRM_FORMAT_P010
|
||||
#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_P210
|
||||
#define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_NV15
|
||||
#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_NV20
|
||||
#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_YUV420_8BIT
|
||||
#define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_YUV420_10BIT
|
||||
#define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_Y210
|
||||
#define DRM_FORMAT_Y210 fourcc_code('Y', '2', '1', '0')
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_VUY888
|
||||
#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4')
|
||||
#endif
|
||||
|
||||
/* ARM AFBC (16x16) */
|
||||
#ifndef DRM_FORMAT_MOD_VENDOR_ARM
|
||||
#define DRM_FORMAT_MOD_VENDOR_ARM 0x08
|
||||
#endif
|
||||
#ifndef DRM_FORMAT_MOD_ARM_TYPE_AFBC
|
||||
#define DRM_FORMAT_MOD_ARM_TYPE_AFBC 0x00
|
||||
#endif
|
||||
#ifndef AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
||||
#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL)
|
||||
#endif
|
||||
#ifndef AFBC_FORMAT_MOD_SPARSE
|
||||
#define AFBC_FORMAT_MOD_SPARSE (1ULL << 6)
|
||||
#endif
|
||||
|
||||
#define drm_is_afbc(mod) \
|
||||
((mod >> 52) == (DRM_FORMAT_MOD_ARM_TYPE_AFBC | \
|
||||
(DRM_FORMAT_MOD_VENDOR_ARM << 4)))
|
||||
|
||||
/* Rockchip RFBC (64x4) */
|
||||
#undef DRM_FORMAT_MOD_VENDOR_ROCKCHIP
|
||||
#define DRM_FORMAT_MOD_VENDOR_ROCKCHIP 0x0b
|
||||
#undef DRM_FORMAT_MOD_ROCKCHIP_TYPE_SHIFT
|
||||
#define DRM_FORMAT_MOD_ROCKCHIP_TYPE_SHIFT 52
|
||||
#undef DRM_FORMAT_MOD_ROCKCHIP_TYPE_MASK
|
||||
#define DRM_FORMAT_MOD_ROCKCHIP_TYPE_MASK 0xf
|
||||
#undef DRM_FORMAT_MOD_ROCKCHIP_TYPE_RFBC
|
||||
#define DRM_FORMAT_MOD_ROCKCHIP_TYPE_RFBC 0x1
|
||||
#undef ROCKCHIP_RFBC_BLOCK_SIZE_64x4
|
||||
#define ROCKCHIP_RFBC_BLOCK_SIZE_64x4 (1ULL)
|
||||
|
||||
#undef fourcc_mod_code
|
||||
#define fourcc_mod_code(vendor, val) \
|
||||
((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL))
|
||||
|
||||
#undef DRM_FORMAT_MOD_ROCKCHIP_CODE
|
||||
#define DRM_FORMAT_MOD_ROCKCHIP_CODE(__type, __val) \
|
||||
fourcc_mod_code(ROCKCHIP, ((__u64)(__type) << DRM_FORMAT_MOD_ROCKCHIP_TYPE_SHIFT) | \
|
||||
((__val) & 0x000fffffffffffffULL))
|
||||
|
||||
#undef DRM_FORMAT_MOD_ROCKCHIP_RFBC
|
||||
#define DRM_FORMAT_MOD_ROCKCHIP_RFBC(mode) \
|
||||
DRM_FORMAT_MOD_ROCKCHIP_CODE(DRM_FORMAT_MOD_ROCKCHIP_TYPE_RFBC, mode)
|
||||
|
||||
#define drm_is_rfbc(mod) \
|
||||
(((mod >> 56) & 0xff) == DRM_FORMAT_MOD_VENDOR_ROCKCHIP) && \
|
||||
(((mod >> 52) & DRM_FORMAT_MOD_ROCKCHIP_TYPE_MASK) == DRM_FORMAT_MOD_ROCKCHIP_TYPE_RFBC)
|
||||
|
||||
/**
|
||||
* DRM Prime Frame descriptor for RKMPP HWDevice.
|
||||
*/
|
||||
typedef struct AVRKMPPDRMFrameDescriptor {
|
||||
/**
|
||||
* Backwards compatibility with AVDRMFrameDescriptor.
|
||||
*/
|
||||
AVDRMFrameDescriptor drm_desc;
|
||||
|
||||
/**
|
||||
* References to MppBuffer instances which are used
|
||||
* on each drm frame index.
|
||||
*/
|
||||
MppBuffer buffers[AV_DRM_MAX_PLANES];
|
||||
} AVRKMPPDRMFrameDescriptor;
|
||||
|
||||
/**
|
||||
* RKMPP-specific data associated with a frame pool.
|
||||
*
|
||||
* Allocated as AVHWFramesContext.hwctx.
|
||||
*/
|
||||
typedef struct AVRKMPPFramesContext {
|
||||
/**
|
||||
* MPP buffer group.
|
||||
*/
|
||||
MppBufferGroup buf_group;
|
||||
/**
|
||||
* MPP buffer allocation flags at frames context level.
|
||||
*/
|
||||
int flags;
|
||||
|
||||
/**
|
||||
* The descriptors of all frames in the pool after creation.
|
||||
* Only valid if AVHWFramesContext.initial_pool_size was positive.
|
||||
* These are intended to be used as the buffer of RKMPP decoder.
|
||||
*/
|
||||
AVRKMPPDRMFrameDescriptor *frames;
|
||||
int nb_frames;
|
||||
} AVRKMPPFramesContext;
|
||||
|
||||
/**
|
||||
* RKMPP device details.
|
||||
*
|
||||
* Allocated as AVHWDeviceContext.hwctx
|
||||
*/
|
||||
typedef struct AVRKMPPDeviceContext {
|
||||
/**
|
||||
* MPP buffer allocation flags at device context level.
|
||||
*/
|
||||
int flags;
|
||||
} AVRKMPPDeviceContext;
|
||||
|
||||
#endif /* AVUTIL_HWCONTEXT_RKMPP_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue