aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0489-staging-bcm2835-codec-Add-support-for-decoding-inter.patch
blob: 7d5162d4fc76db65b59e38aab921272d5d80f29c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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;