+static av_cold int libx265_encode_set_roi(libx265Context *ctx, const AVFrame *frame, x265_picture* pic)
+{
+ AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST);
+ if (sd) {
+ if (ctx->params->rc.aqMode == X265_AQ_NONE) {
+ if (!ctx->roi_warned) {
+ ctx->roi_warned = 1;
+ av_log(ctx, AV_LOG_WARNING, "Adaptive quantization must be enabled to use ROI encoding, skipping ROI.\n");
+ }
+ } else {
+ /* 8x8 block when qg-size is 8, 16*16 block otherwise. */
+ int mb_size = (ctx->params->rc.qgSize == 8) ? 8 : 16;
+ int mbx = (frame->width + mb_size - 1) / mb_size;
+ int mby = (frame->height + mb_size - 1) / mb_size;
+ int qp_range = 51 + 6 * (pic->bitDepth - 8);
+ int nb_rois;
+ const AVRegionOfInterest *roi;
+ uint32_t roi_size;
+ float *qoffsets; /* will be freed after encode is called. */
+
+ roi = (const AVRegionOfInterest*)sd->data;
+ roi_size = roi->self_size;
+ if (!roi_size || sd->size % roi_size != 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid AVRegionOfInterest.self_size.\n");
+ return AVERROR(EINVAL);
+ }
+ nb_rois = sd->size / roi_size;
+
+ qoffsets = av_mallocz_array(mbx * mby, sizeof(*qoffsets));
+ if (!qoffsets)
+ return AVERROR(ENOMEM);
+
+ // This list must be iterated in reverse because the first
+ // region in the list applies when regions overlap.
+ for (int i = nb_rois - 1; i >= 0; i--) {
+ int startx, endx, starty, endy;
+ float qoffset;
+
+ roi = (const AVRegionOfInterest*)(sd->data + roi_size * i);
+
+ starty = FFMIN(mby, roi->top / mb_size);
+ endy = FFMIN(mby, (roi->bottom + mb_size - 1)/ mb_size);
+ startx = FFMIN(mbx, roi->left / mb_size);
+ endx = FFMIN(mbx, (roi->right + mb_size - 1)/ mb_size);
+
+ if (roi->qoffset.den == 0) {
+ av_free(qoffsets);
+ av_log(ctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n");
+ return AVERROR(EINVAL);
+ }
+ qoffset = roi->qoffset.num * 1.0f / roi->qoffset.den;
+ qoffset = av_clipf(qoffset * qp_range, -qp_range, +qp_range);
+
+ for (int y = starty; y < endy; y++)
+ for (int x = startx; x < endx; x++)
+ qoffsets[x + y*mbx] = qoffset;
+ }
+
+ pic->quantOffsets = qoffsets;
+ }
+ }
+ return 0;
+}
+