/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "internal.h" #include "v4l2_request.h" #include "vp89_rac.h" #include "vp9dec.h" #define V4L2_VP9_CONTROLS_MAX 2 typedef struct V4L2RequestContextVP9 { V4L2RequestContext base; bool has_compressed_hdr; } V4L2RequestContextVP9; typedef struct V4L2RequestControlsVP9 { V4L2RequestPictureContext pic; struct v4l2_ctrl_vp9_frame frame; struct v4l2_ctrl_vp9_compressed_hdr compressed_hdr; } V4L2RequestControlsVP9; // differential forward probability updates static int read_prob_delta(VPXRangeCoder *c) { static const uint8_t inv_map_table[255] = { 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189, 202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253, }; int d; /* This code is trying to do a differential probability update. For a * current probability A in the range [1, 255], the difference to a new * probability of any value can be expressed differentially as 1-A, 255-A * where some part of this (absolute range) exists both in positive as * well as the negative part, whereas another part only exists in one * half. We're trying to code this shared part differentially, i.e. * times two where the value of the lowest bit specifies the sign, and * the single part is then coded on top of this. This absolute difference * then again has a value of [0, 254], but a bigger value in this range * indicates that we're further away from the original value A, so we * can code this as a VLC code, since higher values are increasingly * unlikely. The first 20 values in inv_map_table[] allow 'cheap, rough' * updates vs. the 'fine, exact' updates further down the range, which * adds one extra dimension to this differential update model. */ if (!vp89_rac_get(c)) { d = vp89_rac_get_uint(c, 4) + 0; } else if (!vp89_rac_get(c)) { d = vp89_rac_get_uint(c, 4) + 16; } else if (!vp89_rac_get(c)) { d = vp89_rac_get_uint(c, 5) + 32; } else { d = vp89_rac_get_uint(c, 7); if (d >= 65) d = (d << 1) - 65 + vp89_rac_get(c); d += 64; av_assert2(d < FF_ARRAY_ELEMS(inv_map_table)); } return inv_map_table[d]; } static void fill_compressed_hdr(struct v4l2_ctrl_vp9_compressed_hdr *ctrl, const uint8_t *buffer, uint32_t size, AVCodecContext *avctx) { const VP9Context *s = avctx->priv_data; enum CompPredMode comppredmode; int ret, i, j, k, l, m, n; VPXRangeCoder c; ret = ff_vpx_init_range_decoder(&c, buffer + s->s.h.uncompressed_header_size, s->s.h.compressed_header_size); if (ret < 0) return; if (vpx_rac_get_prob_branchy(&c, 128)) // marker bit return; // txfm updates if (s->s.h.lossless) { ctrl->tx_mode = V4L2_VP9_TX_MODE_ONLY_4X4; } else { ctrl->tx_mode = vp89_rac_get_uint(&c, 2); if (ctrl->tx_mode == V4L2_VP9_TX_MODE_ALLOW_32X32) ctrl->tx_mode += vp89_rac_get(&c); if (ctrl->tx_mode == V4L2_VP9_TX_MODE_SELECT) { for (i = 0; i < 2; i++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->tx8[i][0] = read_prob_delta(&c); for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->tx16[i][j] = read_prob_delta(&c); for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->tx32[i][j] = read_prob_delta(&c); } } // coef updates for (i = 0; i < 4; i++) { if (vp89_rac_get(&c)) { for (j = 0; j < 2; j++) for (k = 0; k < 2; k++) for (l = 0; l < 6; l++) for (m = 0; m < 6; m++) { if (m >= 3 && l == 0) // dc only has 3 pt break; for (n = 0; n < 3; n++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->coef[i][j][k][l][m][n] = read_prob_delta(&c); } } if (ctrl->tx_mode == i) break; } // mode updates for (i = 0; i < 3; i++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->skip[i] = read_prob_delta(&c); if (!s->s.h.keyframe && !s->s.h.intraonly) { for (i = 0; i < 7; i++) for (j = 0; j < 3; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->inter_mode[i][j] = read_prob_delta(&c); if (s->s.h.filtermode == FILTER_SWITCHABLE) for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->interp_filter[i][j] = read_prob_delta(&c); for (i = 0; i < 4; i++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->is_inter[i] = read_prob_delta(&c); if (s->s.h.allowcompinter) { comppredmode = vp89_rac_get(&c); if (comppredmode) comppredmode += vp89_rac_get(&c); if (comppredmode == PRED_SWITCHABLE) for (i = 0; i < 5; i++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->comp_mode[i] = read_prob_delta(&c); } else { comppredmode = PRED_SINGLEREF; } if (comppredmode != PRED_COMPREF) { for (i = 0; i < 5; i++) { if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->single_ref[i][0] = read_prob_delta(&c); if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->single_ref[i][1] = read_prob_delta(&c); } } if (comppredmode != PRED_SINGLEREF) { for (i = 0; i < 5; i++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->comp_ref[i] = read_prob_delta(&c); } for (i = 0; i < 4; i++) for (j = 0; j < 9; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->y_mode[i][j] = read_prob_delta(&c); for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->partition[(i * 4) + j][k] = read_prob_delta(&c); // mv fields for (i = 0; i < 3; i++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.joint[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; for (i = 0; i < 2; i++) { if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.sign[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; for (j = 0; j < 10; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.classes[i][j] = (vp89_rac_get_uint(&c, 7) << 1) | 1; if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.class0_bit[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; for (j = 0; j < 10; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.bits[i][j] = (vp89_rac_get_uint(&c, 7) << 1) | 1; } for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) for (k = 0; k < 3; k++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.class0_fr[i][j][k] = (vp89_rac_get_uint(&c, 7) << 1) | 1; for (j = 0; j < 3; j++) if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.fr[i][j] = (vp89_rac_get_uint(&c, 7) << 1) | 1; } if (s->s.h.highprecisionmvs) { for (i = 0; i < 2; i++) { if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.class0_hp[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; if (vpx_rac_get_prob_branchy(&c, 252)) ctrl->mv.hp[i] = (vp89_rac_get_uint(&c, 7) << 1) | 1; } } } memcpy(ctrl->uv_mode, s->prob.p.uv_mode, sizeof(ctrl->uv_mode)); } static void fill_frame(struct v4l2_ctrl_vp9_frame *ctrl, AVCodecContext *avctx) { const VP9Context *s = avctx->priv_data; AVFrame *ref; int i; *ctrl = (struct v4l2_ctrl_vp9_frame) { .lf = { .level = s->s.h.filter.level, .sharpness = s->s.h.filter.sharpness, }, .quant = { .base_q_idx = s->s.h.yac_qi, .delta_q_y_dc = s->s.h.ydc_qdelta, .delta_q_uv_dc = s->s.h.uvdc_qdelta, .delta_q_uv_ac = s->s.h.uvac_qdelta, }, .compressed_header_size = s->s.h.compressed_header_size, .uncompressed_header_size = s->s.h.uncompressed_header_size, .frame_width_minus_1 = avctx->width - 1, .frame_height_minus_1 = avctx->height - 1, .render_width_minus_1 = s->w - 1, .render_height_minus_1 = s->h - 1, .reset_frame_context = s->s.h.resetctx > 0 ? s->s.h.resetctx - 1 : 0, .frame_context_idx = s->s.h.framectxid, .profile = s->s.h.profile, .bit_depth = s->s.h.bpp, .interpolation_filter = s->s.h.filtermode ^ (s->s.h.filtermode <= 1), .tile_cols_log2 = s->s.h.tiling.log2_tile_cols, .tile_rows_log2 = s->s.h.tiling.log2_tile_rows, .reference_mode = s->s.h.comppredmode, }; for (i = 0; i < 4; i++) ctrl->lf.ref_deltas[i] = s->s.h.lf_delta.ref[i]; for (i = 0; i < 2; i++) ctrl->lf.mode_deltas[i] = s->s.h.lf_delta.mode[i]; if (s->s.h.lf_delta.enabled) ctrl->lf.flags |= V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED; if (s->s.h.lf_delta.updated) ctrl->lf.flags |= V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE; for (i = 0; i < 8; i++) { if (s->s.h.segmentation.feat[i].q_enabled) { ctrl->seg.feature_data[i][V4L2_VP9_SEG_LVL_ALT_Q] = s->s.h.segmentation.feat[i].q_val; ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_ALT_Q; } if (s->s.h.segmentation.feat[i].lf_enabled) { ctrl->seg.feature_data[i][V4L2_VP9_SEG_LVL_ALT_L] = s->s.h.segmentation.feat[i].lf_val; ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_ALT_L; } if (s->s.h.segmentation.feat[i].ref_enabled) { ctrl->seg.feature_data[i][V4L2_VP9_SEG_LVL_REF_FRAME] = s->s.h.segmentation.feat[i].ref_val; ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_REF_FRAME; } if (s->s.h.segmentation.feat[i].skip_enabled) ctrl->seg.feature_enabled[i] |= 1 << V4L2_VP9_SEG_LVL_SKIP; } for (i = 0; i < 7; i++) ctrl->seg.tree_probs[i] = s->s.h.segmentation.prob[i]; if (s->s.h.segmentation.temporal) { for (i = 0; i < 3; i++) ctrl->seg.pred_probs[i] = s->s.h.segmentation.pred_prob[i]; } else { memset(ctrl->seg.pred_probs, 255, sizeof(ctrl->seg.pred_probs)); } if (s->s.h.segmentation.enabled) ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_ENABLED; if (s->s.h.segmentation.update_map) ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP; if (s->s.h.segmentation.temporal) ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE; if (s->frame_header->segmentation_update_data) ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA; if (s->s.h.segmentation.absolute_vals) ctrl->seg.flags |= V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE; if (s->s.h.keyframe) ctrl->flags |= V4L2_VP9_FRAME_FLAG_KEY_FRAME; if (!s->s.h.invisible) ctrl->flags |= V4L2_VP9_FRAME_FLAG_SHOW_FRAME; if (s->s.h.errorres) ctrl->flags |= V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT; if (s->s.h.intraonly) ctrl->flags |= V4L2_VP9_FRAME_FLAG_INTRA_ONLY; if (!s->s.h.keyframe && s->s.h.highprecisionmvs) ctrl->flags |= V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV; if (s->s.h.refreshctx) ctrl->flags |= V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX; if (s->s.h.parallelmode) ctrl->flags |= V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE; if (s->ss_h) ctrl->flags |= V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING; if (s->ss_v) ctrl->flags |= V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING; if (avctx->color_range == AVCOL_RANGE_JPEG) ctrl->flags |= V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING; ref = s->s.refs[s->s.h.refidx[0]].f; if (ref && ref->private_ref) ctrl->last_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); ref = s->s.refs[s->s.h.refidx[1]].f; if (ref && ref->private_ref) ctrl->golden_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); ref = s->s.refs[s->s.h.refidx[2]].f; if (ref && ref->private_ref) ctrl->alt_frame_ts = ff_v4l2_request_get_capture_timestamp(ref); if (s->s.h.signbias[0]) ctrl->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_LAST; if (s->s.h.signbias[1]) ctrl->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_GOLDEN; if (s->s.h.signbias[2]) ctrl->ref_frame_sign_bias |= V4L2_VP9_SIGN_BIAS_ALT; } static int v4l2_request_vp9_start_frame(AVCodecContext *avctx, av_unused const AVBufferRef *buf_ref, const uint8_t *buffer, uint32_t size) { const VP9SharedContext *h = avctx->priv_data; const VP9Frame *f = &h->frames[CUR_FRAME]; V4L2RequestContextVP9 *ctx = avctx->internal->hwaccel_priv_data; V4L2RequestControlsVP9 *controls = f->hwaccel_picture_private; int ret; ret = ff_v4l2_request_start_frame(avctx, &controls->pic, f->tf.f); if (ret) return ret; fill_frame(&controls->frame, avctx); if (ctx->has_compressed_hdr) fill_compressed_hdr(&controls->compressed_hdr, buffer, size, avctx); return 0; } static int v4l2_request_vp9_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { const VP9SharedContext *h = avctx->priv_data; V4L2RequestControlsVP9 *controls = h->frames[CUR_FRAME].hwaccel_picture_private; return ff_v4l2_request_append_output(avctx, &controls->pic, buffer, size); } static int v4l2_request_vp9_end_frame(AVCodecContext *avctx) { const VP9SharedContext *h = avctx->priv_data; V4L2RequestContextVP9 *ctx = avctx->internal->hwaccel_priv_data; V4L2RequestControlsVP9 *controls = h->frames[CUR_FRAME].hwaccel_picture_private; int count = 0; struct v4l2_ext_control control[V4L2_VP9_CONTROLS_MAX] = {}; control[count++] = (struct v4l2_ext_control) { .id = V4L2_CID_STATELESS_VP9_FRAME, .ptr = &controls->frame, .size = sizeof(controls->frame), }; if (ctx->has_compressed_hdr) { control[count++] = (struct v4l2_ext_control) { .id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, .ptr = &controls->compressed_hdr, .size = sizeof(controls->compressed_hdr), }; } return ff_v4l2_request_decode_frame(avctx, &controls->pic, control, count); } static int v4l2_request_vp9_post_frames_ctx(AVCodecContext *avctx) { V4L2RequestContextVP9 *ctx = avctx->internal->hwaccel_priv_data; struct v4l2_query_ext_ctrl compressed_hdr = { .id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, }; // TODO: check V4L2_CID_MPEG_VIDEO_VP9_PROFILE // TODO: check V4L2_CID_MPEG_VIDEO_VP9_LEVEL if (!ff_v4l2_request_query_control(avctx, &compressed_hdr)) ctx->has_compressed_hdr = true; else ctx->has_compressed_hdr = false; return 0; } static int v4l2_request_vp9_init(AVCodecContext *avctx) { struct v4l2_ctrl_vp9_frame frame; struct v4l2_ext_control control[] = { { .id = V4L2_CID_STATELESS_VP9_FRAME, .ptr = &frame, .size = sizeof(frame), }, }; fill_frame(&frame, avctx); return ff_v4l2_request_init(avctx, control, FF_ARRAY_ELEMS(control), v4l2_request_vp9_post_frames_ctx); } static int v4l2_request_vp9_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { const VP9Context *s = avctx->priv_data; uint8_t bit_depth = s ? s->s.h.bpp : 0; return ff_v4l2_request_frame_params(avctx, hw_frames_ctx, V4L2_PIX_FMT_VP9_FRAME, bit_depth); } const FFHWAccel ff_vp9_v4l2request_hwaccel = { .p.name = "vp9_v4l2request", .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_VP9, .p.pix_fmt = AV_PIX_FMT_DRM_PRIME, .start_frame = v4l2_request_vp9_start_frame, .decode_slice = v4l2_request_vp9_decode_slice, .end_frame = v4l2_request_vp9_end_frame, .flush = ff_v4l2_request_flush, .frame_priv_data_size = sizeof(V4L2RequestControlsVP9), .init = v4l2_request_vp9_init, .uninit = ff_v4l2_request_uninit, .priv_data_size = sizeof(V4L2RequestContextVP9), .frame_params = v4l2_request_vp9_frame_params, .caps_internal = HWACCEL_CAP_ASYNC_SAFE, };