openwrt/target/linux/bcm27xx/patches-5.15/950-0489-staging-bcm2835-co...

174 lines
6.1 KiB
Diff

From 6c7a2caf88dda1aa4459b80d399da37dff6c6942 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Fri, 18 Dec 2020 19:56:31 +0000
Subject: [PATCH] staging/bcm2835-codec: Add support for decoding
interlaced streams
The video decoder can support decoding interlaced streams, so add
the required plumbing to signal this correctly.
The encoder and ISP do NOT support interlaced data, so trying to
configure an interlaced format on those nodes will be rejected.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
.../bcm2835-codec/bcm2835-v4l2-codec.c | 84 +++++++++++++++++--
1 file changed, 77 insertions(+), 7 deletions(-)
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -619,6 +619,7 @@ struct bcm2835_codec_q_data {
unsigned int crop_height;
bool selection_set;
struct v4l2_fract aspect_ratio;
+ enum v4l2_field field;
unsigned int sizeimage;
unsigned int sequence;
@@ -986,6 +987,10 @@ static void handle_fmt_changed(struct bc
struct bcm2835_codec_q_data *q_data;
struct mmal_msg_event_format_changed *format =
(struct mmal_msg_event_format_changed *)mmal_buf->buffer;
+ struct mmal_parameter_video_interlace_type interlace;
+ int interlace_size = sizeof(interlace);
+ int ret;
+
v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed: buff size min %u, rec %u, buff num min %u, rec %u\n",
__func__,
format->buffer_size_min,
@@ -1029,6 +1034,30 @@ static void handle_fmt_changed(struct bc
q_data->aspect_ratio.numerator = format->es.video.par.num;
q_data->aspect_ratio.denominator = format->es.video.par.den;
+ ret = vchiq_mmal_port_parameter_get(ctx->dev->instance,
+ &ctx->component->output[0],
+ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE,
+ &interlace,
+ &interlace_size);
+ if (!ret) {
+ switch (interlace.mode) {
+ case MMAL_INTERLACE_PROGRESSIVE:
+ default:
+ q_data->field = V4L2_FIELD_NONE;
+ break;
+ case MMAL_INTERLACE_FIELDS_INTERLEAVED_UPPER_FIRST:
+ q_data->field = V4L2_FIELD_INTERLACED_TB;
+ break;
+ case MMAL_INTERLACE_FIELDS_INTERLEAVED_LOWER_FIRST:
+ q_data->field = V4L2_FIELD_INTERLACED_BT;
+ break;
+ }
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: interlace mode %u, v4l2 field %u\n",
+ __func__, interlace.mode, q_data->field);
+ } else {
+ q_data->field = V4L2_FIELD_NONE;
+ }
+
queue_res_chg_event(ctx);
}
@@ -1101,6 +1130,22 @@ static void op_buffer_cb(struct vchiq_mm
vb2->vb2_buf.timestamp = mmal_buf->pts * 1000;
vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length);
+ switch (mmal_buf->mmal_flags &
+ (MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED |
+ MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST)) {
+ case 0:
+ case MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST: /* Bogus */
+ vb2->field = V4L2_FIELD_NONE;
+ break;
+ case MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED:
+ vb2->field = V4L2_FIELD_INTERLACED_BT;
+ break;
+ case (MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED |
+ MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST):
+ vb2->field = V4L2_FIELD_INTERLACED_TB;
+ break;
+ }
+
if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
vb2->flags |= V4L2_BUF_FLAG_KEYFRAME;
@@ -1272,7 +1317,7 @@ static int vidioc_g_fmt(struct bcm2835_c
f->fmt.pix_mp.width = q_data->crop_width;
f->fmt.pix_mp.height = q_data->height;
f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.field = q_data->field;
f->fmt.pix_mp.colorspace = ctx->colorspace;
f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage;
f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline;
@@ -1347,7 +1392,33 @@ static int vidioc_try_fmt(struct bcm2835
memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0,
sizeof(f->fmt.pix_mp.plane_fmt[0].reserved));
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ if (ctx->dev->role == DECODE) {
+ switch (f->fmt.pix_mp.field) {
+ /*
+ * All of this is pretty much guesswork as we'll set the
+ * interlace format correctly come format changed, and signal
+ * it appropriately on each buffer.
+ */
+ default:
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_ANY:
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ f->fmt.pix_mp.field = V4L2_FIELD_INTERLACED;
+ break;
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_INTERLACED_TB:
+ f->fmt.pix_mp.field = V4L2_FIELD_INTERLACED_TB;
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ f->fmt.pix_mp.field = V4L2_FIELD_INTERLACED_BT;
+ break;
+ }
+ } else {
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ }
return 0;
}
@@ -1430,6 +1501,8 @@ static int vidioc_s_fmt(struct bcm2835_c
ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
ctx->quant = f->fmt.pix_mp.quantization;
+ q_data->field = f->fmt.pix_mp.field;
+
/* All parameters should have been set correctly by try_fmt */
q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline;
q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage;
@@ -2429,11 +2502,6 @@ static int bcm2835_codec_buf_prepare(str
if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
if (vbuf->field == V4L2_FIELD_ANY)
vbuf->field = V4L2_FIELD_NONE;
- if (vbuf->field != V4L2_FIELD_NONE) {
- v4l2_err(&ctx->dev->v4l2_dev, "%s field isn't supported\n",
- __func__);
- return -EINVAL;
- }
}
if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
@@ -2735,6 +2803,7 @@ static int bcm2835_codec_open(struct fil
ctx->q_data[V4L2_M2M_SRC].crop_width,
ctx->q_data[V4L2_M2M_SRC].height,
ctx->q_data[V4L2_M2M_SRC].fmt);
+ ctx->q_data[V4L2_M2M_SRC].field = V4L2_FIELD_NONE;
ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH;
ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT;
@@ -2749,6 +2818,7 @@ static int bcm2835_codec_open(struct fil
ctx->q_data[V4L2_M2M_DST].fmt);
ctx->q_data[V4L2_M2M_DST].aspect_ratio.numerator = 1;
ctx->q_data[V4L2_M2M_DST].aspect_ratio.denominator = 1;
+ ctx->q_data[V4L2_M2M_DST].field = V4L2_FIELD_NONE;
ctx->colorspace = V4L2_COLORSPACE_REC709;
ctx->bitrate = 10 * 1000 * 1000;