mirror of
https://github.com/Pixelplanet/Pixel-VR-Player.git
synced 2026-10-20 18:02:13 +02:00
350 lines
13 KiB
Diff
350 lines
13 KiB
Diff
--- a/libavcodec/v4l2_m2m.h
|
|
+++ b/libavcodec/v4l2_m2m.h
|
|
@@ -76,6 +76,12 @@
|
|
|
|
int num_output_buffers;
|
|
int num_capture_buffers;
|
|
+ int drm_prime;
|
|
+ int capture_changed;
|
|
+ int capture_ready;
|
|
+ struct v4l2_rect drm_crop, next_crop;
|
|
+ struct v4l2_format next_format;
|
|
+ uint32_t drm_format;
|
|
} V4L2m2mPriv;
|
|
|
|
/**
|
|
--- a/libavcodec/v4l2_buffers.h
|
|
+++ b/libavcodec/v4l2_buffers.h
|
|
@@ -31,6 +31,7 @@
|
|
#include "libavutil/buffer.h"
|
|
#include "libavutil/frame.h"
|
|
#include "packet.h"
|
|
+#include "libavutil/hwcontext_drm.h"
|
|
|
|
enum V4L2Buffer_status {
|
|
V4L2BUF_AVAILABLE,
|
|
@@ -58,6 +59,7 @@
|
|
} plane_info[VIDEO_MAX_PLANES];
|
|
|
|
int num_planes;
|
|
+ AVDRMFrameDescriptor drm;
|
|
|
|
/* the v4l2_buffer buf.m.planes pointer uses the planes[] mem */
|
|
struct v4l2_buffer buf;
|
|
--- a/libavcodec/v4l2_m2m_dec.c
|
|
+++ b/libavcodec/v4l2_m2m_dec.c
|
|
@@ -51,6 +51,10 @@
|
|
}
|
|
}
|
|
|
|
+ if (((V4L2m2mPriv *)s->priv)->drm_prime &&
|
|
+ !((V4L2m2mPriv *)s->priv)->capture_ready)
|
|
+ return 0;
|
|
+
|
|
if (capture->streamon)
|
|
return 0;
|
|
|
|
@@ -64,6 +68,8 @@
|
|
|
|
/* 2.1 update the AVCodecContext */
|
|
avctx->pix_fmt = ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
|
|
+ if (((V4L2m2mPriv *)s->priv)->drm_prime)
|
|
+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
|
|
capture->av_pix_fmt = avctx->pix_fmt;
|
|
|
|
/* 3. set the crop parameters */
|
|
@@ -140,6 +146,22 @@
|
|
V4L2Context *const output = &s->output;
|
|
int ret;
|
|
|
|
+ if (((V4L2m2mPriv *)s->priv)->capture_changed == 1)
|
|
+ return AVERROR(EAGAIN);
|
|
+ if (((V4L2m2mPriv *)s->priv)->capture_changed == 3)
|
|
+ return ff_v4l2_context_dequeue_frame(capture, frame, -1);
|
|
+ if (((V4L2m2mPriv *)s->priv)->capture_changed == 2) {
|
|
+ V4L2m2mPriv *priv = s->priv;
|
|
+ capture->width = priv->next_format.fmt.pix_mp.width;
|
|
+ capture->height = priv->next_format.fmt.pix_mp.height;
|
|
+ priv->drm_crop = priv->next_crop;
|
|
+ priv->drm_format = priv->next_format.fmt.pix_mp.pixelformat;
|
|
+ ret = ff_v4l2_m2m_codec_reinit(s);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ ((V4L2m2mPriv *)s->priv)->capture_changed = 0;
|
|
+ }
|
|
+
|
|
if (!s->buf_pkt.size) {
|
|
ret = ff_decode_get_packet(avctx, &s->buf_pkt);
|
|
if (ret < 0) {
|
|
@@ -165,7 +187,7 @@
|
|
ret = v4l2_try_start(avctx);
|
|
if (ret) {
|
|
/* cant recover */
|
|
- if (ret != AVERROR(ENOMEM))
|
|
+ if (!((V4L2m2mPriv *)s->priv)->drm_prime && ret != AVERROR(ENOMEM))
|
|
ret = 0;
|
|
goto fail;
|
|
}
|
|
@@ -227,6 +249,10 @@
|
|
V4L_M2M_DEFAULT_OPTS,
|
|
{ "num_capture_buffers", "Number of buffers in the capture context",
|
|
OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 2, INT_MAX, FLAGS },
|
|
+ { "drm_prime", "Export capture buffers as DMA-BUF",
|
|
+ OFFSET(drm_prime), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
|
|
+ { "capture_changed", "Capture pool release (1), released (2), draining (3)",
|
|
+ OFFSET(capture_changed), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 3, FLAGS },
|
|
{ NULL},
|
|
};
|
|
|
|
--- a/libavcodec/v4l2_context.c
|
|
+++ b/libavcodec/v4l2_context.c
|
|
@@ -29,6 +29,7 @@
|
|
#include <poll.h>
|
|
#include "libavcodec/avcodec.h"
|
|
#include "decode.h"
|
|
+#include "libavutil/pixdesc.h"
|
|
#include "v4l2_buffers.h"
|
|
#include "v4l2_fmt.h"
|
|
#include "v4l2_m2m.h"
|
|
@@ -200,6 +201,29 @@
|
|
return 0;
|
|
}
|
|
|
|
+ if (((V4L2m2mPriv *)s->priv)->drm_prime) {
|
|
+ V4L2m2mPriv *priv = s->priv;
|
|
+ struct v4l2_selection selection = {
|
|
+ .type = s->capture.type,
|
|
+ .target = V4L2_SEL_TGT_COMPOSE,
|
|
+ };
|
|
+ if (ioctl(s->fd, VIDIOC_G_SELECTION, &selection)) {
|
|
+ av_log(logger(ctx), AV_LOG_ERROR, "capture VIDIOC_G_SELECTION: %s\n", strerror(errno));
|
|
+ return AVERROR(errno);
|
|
+ }
|
|
+ priv->next_crop = selection.r;
|
|
+ priv->next_format = cap_fmt;
|
|
+ if (s->capture.buffers) {
|
|
+ priv->capture_changed = 3;
|
|
+ return 0;
|
|
+ }
|
|
+ priv->drm_crop = selection.r;
|
|
+ priv->capture_ready = 1;
|
|
+ s->capture.height = v4l2_get_height(&cap_fmt);
|
|
+ s->capture.width = v4l2_get_width(&cap_fmt);
|
|
+ priv->drm_format = cap_fmt.fmt.pix_mp.pixelformat;
|
|
+ return 1;
|
|
+ }
|
|
if (v4l2_resolution_changed(&s->capture, &cap_fmt)) {
|
|
s->capture.height = v4l2_get_height(&cap_fmt);
|
|
s->capture.width = v4l2_get_width(&cap_fmt);
|
|
@@ -310,7 +334,8 @@
|
|
pfd.events = POLLOUT | POLLWRNORM;
|
|
else {
|
|
/* no need to listen to requests for more input while draining */
|
|
- if (ctx_to_m2mctx(ctx)->draining)
|
|
+ if (ctx_to_m2mctx(ctx)->draining ||
|
|
+ ((V4L2m2mPriv *)ctx_to_m2mctx(ctx)->priv)->capture_changed == 3)
|
|
pfd.events = POLLIN | POLLRDNORM | POLLPRI;
|
|
}
|
|
|
|
@@ -395,6 +420,13 @@
|
|
return NULL;
|
|
}
|
|
|
|
+ if (!V4L2_TYPE_IS_OUTPUT(ctx->type) &&
|
|
+ ((V4L2m2mPriv *)ctx_to_m2mctx(ctx)->priv)->capture_changed == 3 &&
|
|
+ (buf.flags & V4L2_BUF_FLAG_LAST)) {
|
|
+ ((V4L2m2mPriv *)ctx_to_m2mctx(ctx)->priv)->capture_changed = 1;
|
|
+ ctx_to_m2mctx(ctx)->reinit = 1;
|
|
+ return NULL;
|
|
+ }
|
|
if (ctx_to_m2mctx(ctx)->draining && !V4L2_TYPE_IS_OUTPUT(ctx->type)) {
|
|
int bytesused = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ?
|
|
buf.m.planes[0].bytesused : buf.bytesused;
|
|
@@ -452,6 +484,9 @@
|
|
for (i = 0; i < ctx->num_buffers; i++) {
|
|
V4L2Buffer *buffer = &ctx->buffers[i];
|
|
|
|
+ for (j = 0; j < buffer->drm.nb_objects; j++)
|
|
+ close(buffer->drm.objects[j].fd);
|
|
+
|
|
for (j = 0; j < buffer->num_planes; j++) {
|
|
struct V4L2Plane_info *p = &buffer->plane_info[j];
|
|
if (p->mm_addr && p->length)
|
|
@@ -668,6 +703,22 @@
|
|
struct v4l2_format_update fmt = { 0 };
|
|
int ret;
|
|
|
|
+ if (ctx->av_codec_id == AV_CODEC_ID_RAWVIDEO &&
|
|
+ ((V4L2m2mPriv *)ctx_to_m2mctx(ctx)->priv)->drm_prime) {
|
|
+ AVCodecContext *avctx = ctx_to_m2mctx(ctx)->avctx;
|
|
+ V4L2m2mPriv *priv = ctx_to_m2mctx(ctx)->priv;
|
|
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
|
|
+ if (!V4L2_TYPE_IS_MULTIPLANAR(ctx->type) || (!priv->drm_format && !desc))
|
|
+ return AVERROR(EINVAL);
|
|
+ if (!priv->drm_format)
|
|
+ priv->drm_format = desc->comp[0].depth == 10 ?
|
|
+ v4l2_fourcc('Q', '1', '0', 'C') : V4L2_PIX_FMT_NV12;
|
|
+ fmt.v4l2_fmt = priv->drm_format;
|
|
+ fmt.update_v4l2 = 1;
|
|
+ v4l2_save_to_context(ctx, &fmt);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
if (ctx->av_codec_id == AV_CODEC_ID_RAWVIDEO) {
|
|
ret = v4l2_get_raw_format(ctx, &fmt.av_fmt);
|
|
if (ret)
|
|
@@ -714,6 +765,7 @@
|
|
V4L2m2mContext *s = ctx_to_m2mctx(ctx);
|
|
struct v4l2_requestbuffers req;
|
|
int ret, i;
|
|
+ unsigned required = 0;
|
|
|
|
if (!v4l2_type_supported(ctx)) {
|
|
av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
|
|
@@ -728,12 +780,23 @@
|
|
req.count = ctx->num_buffers;
|
|
req.memory = V4L2_MEMORY_MMAP;
|
|
req.type = ctx->type;
|
|
+ if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ((V4L2m2mPriv *)s->priv)->drm_prime) {
|
|
+ req.count = 1;
|
|
+ req.memory = V4L2_MEMORY_DMABUF;
|
|
+ if (ioctl(s->fd, VIDIOC_REQBUFS, &req))
|
|
+ return AVERROR(errno);
|
|
+ req.memory = V4L2_MEMORY_MMAP;
|
|
+ req.count += ((V4L2m2mPriv *)s->priv)->num_capture_buffers;
|
|
+ required = req.count;
|
|
+ }
|
|
ret = ioctl(s->fd, VIDIOC_REQBUFS, &req);
|
|
if (ret < 0) {
|
|
av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_REQBUFS failed: %s\n", ctx->name, strerror(errno));
|
|
return AVERROR(errno);
|
|
}
|
|
|
|
+ if (req.count < required)
|
|
+ return AVERROR(ENOMEM);
|
|
ctx->num_buffers = req.count;
|
|
ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer));
|
|
if (!ctx->buffers) {
|
|
--- a/libavcodec/v4l2_buffers.c
|
|
+++ b/libavcodec/v4l2_buffers.c
|
|
@@ -21,6 +21,7 @@
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
+#define _GNU_SOURCE
|
|
#include <linux/videodev2.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
@@ -296,11 +297,68 @@
|
|
return 0;
|
|
}
|
|
|
|
+static int v4l2_export_buffer(V4L2Buffer *buffer)
|
|
+{
|
|
+ struct v4l2_pix_format_mplane *f = &buffer->context->format.fmt.pix_mp;
|
|
+ AVDRMFrameDescriptor *drm = &buffer->drm;
|
|
+ size_t pitch = f->plane_fmt[0].bytesperline;
|
|
+ size_t offset = pitch * f->height;
|
|
+ struct v4l2_exportbuffer exp = {
|
|
+ .type = buffer->context->type,
|
|
+ .index = buffer->buf.index,
|
|
+ .flags = O_CLOEXEC | O_RDWR,
|
|
+ };
|
|
+ off_t size;
|
|
+ uint64_t modifier = 0;
|
|
+ uint32_t format = V4L2_PIX_FMT_NV12;
|
|
+
|
|
+ if (buffer->num_planes != 1)
|
|
+ return AVERROR(ENOSYS);
|
|
+ if (f->pixelformat == v4l2_fourcc('Q', '1', '0', 'C')) {
|
|
+ size_t meta_stride = FFALIGN((f->width + 47) / 48, 64);
|
|
+ size_t meta_height = FFALIGN((f->height + 3) / 4, 16);
|
|
+ offset = FFALIGN(meta_stride * meta_height, 4096) + FFALIGN(offset, 4096);
|
|
+ modifier = UINT64_C(0x0500000000000001);
|
|
+ format = v4l2_fourcc('P', '0', '1', '0');
|
|
+ } else if (f->pixelformat != V4L2_PIX_FMT_NV12) {
|
|
+ return AVERROR(ENOSYS);
|
|
+ }
|
|
+ if (!pitch || offset >= buffer->plane_info[0].length)
|
|
+ return AVERROR_INVALIDDATA;
|
|
+ if (ioctl(buf_to_m2mctx(buffer)->fd, VIDIOC_EXPBUF, &exp))
|
|
+ return AVERROR(errno);
|
|
+ size = lseek(exp.fd, 0, SEEK_END);
|
|
+ if (size < 0 || (uint64_t)size < buffer->plane_info[0].length || lseek(exp.fd, 0, SEEK_SET) < 0) {
|
|
+ close(exp.fd);
|
|
+ return AVERROR_INVALIDDATA;
|
|
+ }
|
|
+ drm->nb_objects = drm->nb_layers = 1;
|
|
+ drm->objects[0] = (AVDRMObjectDescriptor){exp.fd, size, modifier};
|
|
+ drm->layers[0].format = format;
|
|
+ drm->layers[0].nb_planes = 2;
|
|
+ drm->layers[0].planes[0] = (AVDRMPlaneDescriptor){0, 0, pitch};
|
|
+ drm->layers[0].planes[1] = (AVDRMPlaneDescriptor){0, offset, pitch};
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
|
|
{
|
|
int i, ret;
|
|
|
|
frame->format = avbuf->context->av_pix_fmt;
|
|
+ if (frame->format == AV_PIX_FMT_DRM_PRIME) {
|
|
+ ret = v4l2_buf_increase_ref(avbuf);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ frame->buf[0] = av_buffer_create((uint8_t *)&avbuf->drm, sizeof(avbuf->drm),
|
|
+ v4l2_free_buffer, avbuf, AV_BUFFER_FLAG_READONLY);
|
|
+ if (!frame->buf[0]) {
|
|
+ v4l2_free_buffer(avbuf, NULL);
|
|
+ return AVERROR(ENOMEM);
|
|
+ }
|
|
+ frame->data[0] = frame->buf[0]->data;
|
|
+ return 0;
|
|
+ }
|
|
|
|
for (i = 0; i < avbuf->num_planes; i++) {
|
|
ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]);
|
|
@@ -439,6 +497,19 @@
|
|
/* these values are updated also during re-init in v4l2_process_driver_event */
|
|
frame->height = avbuf->context->height;
|
|
frame->width = avbuf->context->width;
|
|
+ if (frame->format == AV_PIX_FMT_DRM_PRIME) {
|
|
+ struct v4l2_rect crop = ((V4L2m2mPriv *)buf_to_m2mctx(avbuf)->priv)->drm_crop;
|
|
+ frame->width = avbuf->context->format.fmt.pix_mp.width;
|
|
+ frame->height = avbuf->context->format.fmt.pix_mp.height;
|
|
+ if (crop.left < 0 || crop.top < 0 || !crop.width || !crop.height ||
|
|
+ crop.left + (uint64_t)crop.width > frame->width ||
|
|
+ crop.top + (uint64_t)crop.height > frame->height)
|
|
+ return AVERROR_INVALIDDATA;
|
|
+ frame->crop_left = crop.left;
|
|
+ frame->crop_top = crop.top;
|
|
+ frame->crop_right = frame->width - crop.left - crop.width;
|
|
+ frame->crop_bottom = frame->height - crop.top - crop.height;
|
|
+ }
|
|
frame->sample_aspect_ratio = avbuf->context->sample_aspect_ratio;
|
|
|
|
/* 3. report errors upstream */
|
|
@@ -525,6 +596,10 @@
|
|
ctx->format.fmt.pix_mp.plane_fmt[i].bytesperline :
|
|
ctx->format.fmt.pix.bytesperline;
|
|
|
|
+ if (ctx->av_pix_fmt == AV_PIX_FMT_DRM_PRIME && !V4L2_TYPE_IS_OUTPUT(ctx->type)) {
|
|
+ avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length;
|
|
+ continue;
|
|
+ }
|
|
if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
|
|
avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length;
|
|
avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length,
|
|
@@ -541,6 +616,11 @@
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
|
|
+ if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx->av_pix_fmt == AV_PIX_FMT_DRM_PRIME) {
|
|
+ ret = v4l2_export_buffer(avbuf);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
avbuf->status = V4L2BUF_AVAILABLE;
|
|
|
|
if (V4L2_TYPE_IS_OUTPUT(ctx->type))
|