Le jeudi 12 janvier 2023 à 12:21 -0300, Ezequiel Garcia a écrit : > On Thu, Jan 12, 2023 at 9:56 AM Sebastian Fricke > <sebastian.fricke@xxxxxxxxxxxxx> wrote: > > > > Implement the valid format and sps validation callbacks for H264. > > H264 already has a SPS validation function, adjust it to fit the > > function the declaration and add error messages. > > Additionally, add a function to fetch attributes from the SPS in a human > > readable format to make the code more self documenting. > > > > Signed-off-by: Sebastian Fricke <sebastian.fricke@xxxxxxxxxxxxx> > > --- > > drivers/staging/media/rkvdec/rkvdec-h264.c | 105 ++++++++++++++++++++++------- > > 1 file changed, 80 insertions(+), 25 deletions(-) > > > > diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c > > index 4fc167b42cf0..17b215874ddd 100644 > > --- a/drivers/staging/media/rkvdec/rkvdec-h264.c > > +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c > > @@ -1026,40 +1026,80 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, > > return 0; > > } > > > > -static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, > > - const struct v4l2_ctrl_h264_sps *sps) > > +/* > > + * Convert some fields from the SPS structure into human readable attributes. > > + */ > > +static int rkvdec_h264_get_sps_attributes(struct rkvdec_ctx *ctx, void *sps, > > + struct sps_attributes *attributes) > > +{ > > + struct v4l2_ctrl_h264_sps *h264_sps = sps; > > + unsigned int width = (h264_sps->pic_width_in_mbs_minus1 + 1) * 16; > > + unsigned int height = (h264_sps->pic_height_in_map_units_minus1 + 1) * 16; > > + /* > > + * When frame_mbs_only_flag is not set, this is field height, > > + * which is half the final height (see (7-18) in the > > + * specification) > > + */ > > + if (!(h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) > > + height *= 2; > > + > > + attributes->width = width; > > + attributes->height = height; > > + attributes->luma_bitdepth = h264_sps->bit_depth_luma_minus8 + 8; > > + attributes->chroma_bitdepth = h264_sps->bit_depth_chroma_minus8 + 8; > > + switch (h264_sps->chroma_format_idc) { > > + case 0: > > + attributes->subsampling = 400; > > + break; > > + case 1: > > + attributes->subsampling = 420; > > + break; > > + case 2: > > + attributes->subsampling = 422; > > + break; > > + case 3: > > + attributes->subsampling = 444; > > + break; > > + }; > > + return 0; > > +} > > + > > +static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, void *sps, > > + struct v4l2_pix_format_mplane *pix_mp) > > { > > - unsigned int width, height; > > + struct sps_attributes attributes = {0}; > > + > > + rkvdec_h264_get_sps_attributes(ctx, sps, &attributes); > > > > /* > > * TODO: The hardware supports 10-bit and 4:2:2 profiles, > > * but it's currently broken in the driver. > > * Reject them for now, until it's fixed. > > */ > > - if (sps->chroma_format_idc > 1) > > - /* Only 4:0:0 and 4:2:0 are supported */ > > + if (attributes.subsampling > 420) { > > + dev_err(ctx->dev->dev, > > + "Only 4:0:0 and 4:2:0 subsampling schemes are supported, got: %d\n", > > + attributes.subsampling); > > return -EINVAL; > > - if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) > > - /* Luma and chroma bit depth mismatch */ > > + } > > + if (attributes.luma_bitdepth != attributes.chroma_bitdepth) { > > + dev_err(ctx->dev->dev, > > + "Luma and chroma bit depth mismatch, luma %d, chroma %d\n", > > + attributes.luma_bitdepth, attributes.chroma_bitdepth); > > return -EINVAL; > > - if (sps->bit_depth_luma_minus8 != 0) > > - /* Only 8-bit is supported */ > > + } > > + if (attributes.luma_bitdepth != 8) { > > + dev_err(ctx->dev->dev, "Only 8-bit H264 formats supported, SPS %d\n", > > + attributes.luma_bitdepth); > > return -EINVAL; > > + } > > > > - width = (sps->pic_width_in_mbs_minus1 + 1) * 16; > > - height = (sps->pic_height_in_map_units_minus1 + 1) * 16; > > - > > - /* > > - * When frame_mbs_only_flag is not set, this is field height, > > - * which is half the final height (see (7-18) in the > > - * specification) > > - */ > > - if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) > > - height *= 2; > > - > > - if (width > ctx->coded_fmt.fmt.pix_mp.width || > > - height > ctx->coded_fmt.fmt.pix_mp.height) > > + if (attributes.width > pix_mp->width || attributes.height > pix_mp->height) { > > + dev_err(ctx->dev->dev, > > + "Incompatible SPS dimension, SPS %dx%d, Pixel format %dx%d.", > > + attributes.width, attributes.height, pix_mp->width, pix_mp->height); > > return -EINVAL; > > + } > > > > return 0; > > } > > @@ -1077,8 +1117,9 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx) > > if (!ctrl) > > return -EINVAL; > > > > - ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); > > - if (ret) > > + ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps, > > + &ctx->coded_fmt.fmt.pix_mp); > > Not a problem with this patch, but I wonder why we accepted a validation > in the start_streaming step. Its something we've been discussing a lot lately Benjamin / Sebastian an I (in person, sorry for that, but sometimes we work better off chats). This is something none of the reviewers/authors seems to have actually cared about so far. In stateless decoders we have FMT(OUTPUT) that contains the coded size, S_CTRL(SOME_HEADERS) which is restricted by the size in FMT(OUTPUT) (restrictions depends on the codec, could be ==, or smaller) but also used to create and limit what FMT(CAPTURE) can be. One thing that raised, is that the width/height alignment has been carelessly applied to OUTPUT and CAPTURE, saved by the fact the real value is in SPS, but possibly leading to strange bugs. Notably we notice that some coded sizes rejected by S_FMT(OUTOUT) still lead to working streamon and decode :-S. The other aspect is validation. The initial thinking was that we can validate the SPS (SOME_HEADERS) directly when the control is set. But we found a gap, userspace could come back and change the coded size in FMT(OUTPUT) to miss-match the header. We can't reject that, since FMT(OUTPUT) should just always works, its the first step according to the doc. The doc does not impose closing the device and restarting from scratch (even though this is what our userspace currently though). So in short, if the SPS coded size no longer match the OUTPUT reported coded size, we needed to reject streamon, hence the validation there. Of course, there was some more mistakes done, like trying to validate when executing a job, but I think all of these got caught at review. On of the reflection we have, is that to be more "semantically" aligned with V4L2 control framework, we should instead of this ensure the the SPS is always valid. But this is a bit of work for a usecase that no one needs. In short, S_FMT(OUTPUT) would always reset the SPS by creating one that is valid and maches the coded size (when the bitstream header have that, the reason its duplicated is that we wanted to support light coding format which does not carry that information in the bitstream). The FMT(CAPTURE) would also be reset to something valid according to both. Then we'd validate the SPS control against the FMT(OUTPUT) when set, and always reset the FMT(CAPTURE) accordingly. This way, no more validation would be required at streamon, since we ensure everything stay valid by discarding past settings. Such a method needs careful thought, and remember a bit of work, but it would help prevent further broken logic, for those who haven't noticed, Hantro G2 HEVC decoder will pick NV12_4L4 by default when you pass a 10bit SPS, cause no one noticed until today ... But that's not what the spec is expecting, as its not a "native" format for the bitstream. What I like about this proposal is that it would remove any remaining possible side effect from a previous session, trully allowing for reuse of codec instance, but again, this is theoritical, as long as you can't crash the driver (which the current validation is about), its not a real bug, most userspace will just set everything all the time with these CODEC. Ok, this is getting long, but I just want to keep in mind this is multiple years of accumulated mistakes (or just delaying known limitation in driver designs), we should probably not block features completely over getting this right immediately, as all it does it makes the actual suffer longer. Though, we should encourage cross-driver fixes whenever something is improved in one driver. > > At this point, the driver accepted all the format negotiations in try_fmt. > It's difficult for applications to recover from this, as there would > be no way to tell what failed, > we would be returning EINVAL, which as per the spec is "buffer type is > not supported, > or no buffers have been allocated (memory mapping) or enqueued (output) yet.". > > I think it would really make a lot of sense to fix this now, instead of continue > abusing it. And also, I'd like to prevent a possible anti-pattern from > spreading. > > Thanks! > Ezequiel > > > + if (ret < 0) > > return ret; > > > > h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); > > @@ -1175,10 +1216,21 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) > > return 0; > > } > > > > +static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx) > > +{ > > + /* > > + * Only 8 bit 4:0:0 and 4:2:0 formats supported for now. > > + * The SPS is validated at a different function thus we can assume that > > + * it is correct. > > + */ > > + return V4L2_PIX_FMT_NV12; > > +} > > + > > static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) > > { > > if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) > > - return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); > > + return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps, > > + &ctx->coded_fmt.fmt.pix_mp); > > > > return 0; > > } > > @@ -1189,4 +1241,7 @@ const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = { > > .stop = rkvdec_h264_stop, > > .run = rkvdec_h264_run, > > .try_ctrl = rkvdec_h264_try_ctrl, > > + .valid_fmt = rkvdec_h264_valid_fmt, > > + .sps_check = rkvdec_h264_validate_sps, > > + .get_sps_attributes = rkvdec_h264_get_sps_attributes, > > }; > > > > -- > > 2.25.1