mirror of
https://github.com/nyanmisaka/ffmpeg-rockchip.git
synced 2025-09-26 21:03:43 +08:00

fix width stride align 16 of rgb24 in rga3. Signed-off-by: nyanmisaka <nst799610810@gmail.com>
603 lines
19 KiB
C
603 lines
19 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|
|
hwfc->internal->pool_internal =
|
|
av_buffer_pool_init2(sizeof(AVRKMPPDRMFrameDescriptor), hwfc,
|
|
rkmpp_drm_pool_alloc, NULL);
|
|
if (!hwfc->internal->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
|
|
},
|
|
};
|