From 44a21e358057a053a47c5f2c071e9f0befb6a601 Mon Sep 17 00:00:00 2001 From: Dave Stevenson 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 --- .../bcm2835-codec/bcm2835-v4l2-codec.c | 84 ++++++++++++++++++++-- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index 4c01bc4..3f15c20 100644 --- 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 bcm2835_codec_ctx *ctx, 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 bcm2835_codec_ctx *ctx, 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_mmal_instance *instance, 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_codec_ctx *ctx, struct v4l2_format *f) 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_codec_ctx *ctx, struct v4l2_format *f, 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_codec_ctx *ctx, struct v4l2_format *f, 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(struct vb2_buffer *vb) 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 file *file) 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 file *file) 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; -- 2.7.4