/* * Copyright © 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Zhou Chang * */ #include #include #include #include #include "intel_batchbuffer.h" #include "intel_driver.h" #include "i965_defines.h" #include "i965_drv_video.h" #include "i965_encoder.h" #include "gen6_vme.h" #include "gen6_mfc.h" #include "i965_post_processing.h" #include "i965_encoder_api.h" #include "i965_avc_encoder_common.h" static struct intel_fraction reduce_fraction(struct intel_fraction f) { unsigned int a = f.num, b = f.den, c; while ((c = a % b)) { a = b; b = c; } return (struct intel_fraction) { f.num / b, f.den / b }; } static VAStatus clear_border(struct object_surface *obj_surface) { int width[3], height[3], hstride[3], vstride[3]; /* in byte */ int planes; unsigned char* p; int i, j; if (obj_surface->border_cleared) return VA_STATUS_SUCCESS; if (obj_surface->fourcc == VA_FOURCC_NV12) { planes = 2; width[0] = width[1] = obj_surface->orig_width; height[0] = obj_surface->orig_height; height[1] = obj_surface->orig_height / 2; hstride[0] = hstride[1] = obj_surface->width; vstride[0] = obj_surface->height; vstride[1] = obj_surface->height / 2; } else { /* todo add P010 */ return VA_STATUS_SUCCESS; } drm_intel_gem_bo_map_gtt(obj_surface->bo); p = (unsigned char*)obj_surface->bo->virtual; if (!p) return VA_STATUS_ERROR_INVALID_SURFACE; for (i = 0; i < planes; i++) { int w = width[i]; int h = height[i]; int hs = hstride[i]; int vs = vstride[i]; /* right */ for (j = 0; j < h; j++) { memset(p + w, 0, hs - w); p += hs; } /* bottom */ for (/* nothing */; j < vs; j++) { memset(p, 0, hs); p += hs; } } drm_intel_gem_bo_unmap_gtt(obj_surface->bo); obj_surface->border_cleared = true; return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_yuv_surface(VADriverContextP ctx, VAProfile profile, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct i965_surface src_surface, dst_surface; struct object_surface *obj_surface; VAStatus status; VARectangle rect; int format = VA_RT_FORMAT_YUV420; unsigned int fourcc = VA_FOURCC_NV12; /* releae the temporary surface */ if (encoder_context->is_tmp_id) { i965_DestroySurfaces(ctx, &encoder_context->input_yuv_surface, 1); encode_state->input_yuv_object = NULL; } encoder_context->is_tmp_id = 0; obj_surface = SURFACE(encode_state->current_render_target); assert(obj_surface && obj_surface->bo); if (!obj_surface || !obj_surface->bo) return VA_STATUS_ERROR_INVALID_PARAMETER; if (VAProfileHEVCMain10 == profile && obj_surface->fourcc != VA_FOURCC_P010) return VA_STATUS_ERROR_INVALID_PARAMETER; if (obj_surface->fourcc == VA_FOURCC_NV12 || (VAProfileHEVCMain10 == profile && obj_surface->fourcc == VA_FOURCC_P010)) { unsigned int tiling = 0, swizzle = 0; dri_bo_get_tiling(obj_surface->bo, &tiling, &swizzle); if (tiling == I915_TILING_Y) { encoder_context->input_yuv_surface = encode_state->current_render_target; encode_state->input_yuv_object = obj_surface; return clear_border(obj_surface); } } if (VAProfileHEVCMain10 == profile) { format = VA_RT_FORMAT_YUV420_10BPP; fourcc = VA_FOURCC_P010; } rect.x = 0; rect.y = 0; rect.width = obj_surface->orig_width; rect.height = obj_surface->orig_height; src_surface.base = (struct object_base *)obj_surface; src_surface.type = I965_SURFACE_TYPE_SURFACE; src_surface.flags = I965_SURFACE_FLAG_FRAME; status = i965_CreateSurfaces(ctx, obj_surface->orig_width, obj_surface->orig_height, format, 1, &encoder_context->input_yuv_surface); ASSERT_RET(status == VA_STATUS_SUCCESS, status); obj_surface = SURFACE(encoder_context->input_yuv_surface); encode_state->input_yuv_object = obj_surface; assert(obj_surface); i965_check_alloc_surface_bo(ctx, obj_surface, 1, fourcc, SUBSAMPLE_YUV420); dst_surface.base = (struct object_base *)obj_surface; dst_surface.type = I965_SURFACE_TYPE_SURFACE; dst_surface.flags = I965_SURFACE_FLAG_FRAME; status = i965_image_processing(ctx, &src_surface, &rect, &dst_surface, &rect); assert(status == VA_STATUS_SUCCESS); encoder_context->is_tmp_id = 1; return clear_border(obj_surface); } static VAStatus intel_encoder_check_jpeg_yuv_surface(VADriverContextP ctx, VAProfile profile, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct i965_surface src_surface, dst_surface; struct object_surface *obj_surface; VAStatus status; VARectangle rect; int format = 0, fourcc = 0, subsample = 0; /* releae the temporary surface */ if (encoder_context->is_tmp_id) { i965_DestroySurfaces(ctx, &encoder_context->input_yuv_surface, 1); encode_state->input_yuv_object = NULL; } encoder_context->is_tmp_id = 0; obj_surface = SURFACE(encode_state->current_render_target); assert(obj_surface && obj_surface->bo); if (!obj_surface || !obj_surface->bo) return VA_STATUS_ERROR_INVALID_PARAMETER; unsigned int tiling = 0, swizzle = 0; dri_bo_get_tiling(obj_surface->bo, &tiling, &swizzle); if (tiling == I915_TILING_Y) { if ((obj_surface->fourcc == VA_FOURCC_NV12) || (obj_surface->fourcc == VA_FOURCC_UYVY) || (obj_surface->fourcc == VA_FOURCC_YUY2) || (obj_surface->fourcc == VA_FOURCC_Y800) || (obj_surface->fourcc == VA_FOURCC_RGBA) || (obj_surface->fourcc == VA_FOURCC_444P)) { encoder_context->input_yuv_surface = encode_state->current_render_target; encode_state->input_yuv_object = obj_surface; return VA_STATUS_SUCCESS; } } rect.x = 0; rect.y = 0; rect.width = obj_surface->orig_width; rect.height = obj_surface->orig_height; src_surface.base = (struct object_base *)obj_surface; src_surface.type = I965_SURFACE_TYPE_SURFACE; src_surface.flags = I965_SURFACE_FLAG_FRAME; switch (obj_surface->fourcc) { case VA_FOURCC_YUY2: fourcc = VA_FOURCC_YUY2; format = VA_RT_FORMAT_YUV422; subsample = SUBSAMPLE_YUV422H; break; case VA_FOURCC_UYVY: fourcc = VA_FOURCC_UYVY; format = VA_RT_FORMAT_YUV422; subsample = SUBSAMPLE_YUV422H; break; case VA_FOURCC_Y800: fourcc = VA_FOURCC_Y800; format = VA_RT_FORMAT_YUV400; subsample = SUBSAMPLE_YUV400; break; case VA_FOURCC_444P: fourcc = VA_FOURCC_444P; format = VA_RT_FORMAT_YUV444; subsample = SUBSAMPLE_YUV444; break; case VA_FOURCC_RGBA: fourcc = VA_FOURCC_RGBA; format = VA_RT_FORMAT_RGB32; subsample = SUBSAMPLE_RGBX; break; default: //All other scenarios will have NV12 format fourcc = VA_FOURCC_NV12; format = VA_RT_FORMAT_YUV420; subsample = SUBSAMPLE_YUV420; break; } status = i965_CreateSurfaces(ctx, obj_surface->orig_width, obj_surface->orig_height, format, 1, &encoder_context->input_yuv_surface); assert(status == VA_STATUS_SUCCESS); if (status != VA_STATUS_SUCCESS) return status; obj_surface = SURFACE(encoder_context->input_yuv_surface); encode_state->input_yuv_object = obj_surface; assert(obj_surface); i965_check_alloc_surface_bo(ctx, obj_surface, 1, fourcc, subsample); dst_surface.base = (struct object_base *)obj_surface; dst_surface.type = I965_SURFACE_TYPE_SURFACE; dst_surface.flags = I965_SURFACE_FLAG_FRAME; //The Y800 format is expected to be tiled. //Linear Y800 is a corner case and needs code in the i965_image_processing. if (obj_surface->fourcc != VA_FOURCC_Y800) { status = i965_image_processing(ctx, &src_surface, &rect, &dst_surface, &rect); assert(status == VA_STATUS_SUCCESS); } encoder_context->is_tmp_id = 1; return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_brc_h264_sequence_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, unsigned int *seq_bits_per_second) { VAEncSequenceParameterBufferH264 *seq_param = (VAEncSequenceParameterBufferH264 *)encode_state->seq_param_ext->buffer; struct intel_fraction framerate; unsigned short num_pframes_in_gop, num_bframes_in_gop; if (!encoder_context->is_new_sequence) return VA_STATUS_SUCCESS; assert(seq_param); if (!seq_param->num_units_in_tick || !seq_param->time_scale) { framerate = (struct intel_fraction) { 30, 1 }; } else { // for the highest layer framerate = (struct intel_fraction) { seq_param->time_scale, 2 * seq_param->num_units_in_tick }; } framerate = reduce_fraction(framerate); encoder_context->brc.num_iframes_in_gop = 1; // Always 1 if (seq_param->intra_period == 0) { // E.g. IDRPP... / IDR(PBB)... (no IDR/I any more) if (seq_param->ip_period == 0) goto error; encoder_context->brc.gop_size = (framerate.num + framerate.den - 1) / framerate.den; // fake num_pframes_in_gop = (encoder_context->brc.gop_size + seq_param->ip_period - 1) / seq_param->ip_period - 1; } else if (seq_param->intra_period == 1) { // E.g. IDRIII... encoder_context->brc.gop_size = 1; num_pframes_in_gop = 0; } else { if (seq_param->ip_period == 0) goto error; encoder_context->brc.gop_size = seq_param->intra_period; num_pframes_in_gop = (encoder_context->brc.gop_size + seq_param->ip_period - 1) / seq_param->ip_period - 1; } num_bframes_in_gop = (encoder_context->brc.gop_size - encoder_context->brc.num_iframes_in_gop - num_pframes_in_gop); if (num_pframes_in_gop != encoder_context->brc.num_pframes_in_gop || num_bframes_in_gop != encoder_context->brc.num_bframes_in_gop || framerate.num != encoder_context->brc.framerate[encoder_context->layer.num_layers - 1].num || framerate.den != encoder_context->brc.framerate[encoder_context->layer.num_layers - 1].den) { encoder_context->brc.num_pframes_in_gop = num_pframes_in_gop; encoder_context->brc.num_bframes_in_gop = num_bframes_in_gop; encoder_context->brc.framerate[encoder_context->layer.num_layers - 1] = framerate; encoder_context->brc.need_reset = 1; } if (!encoder_context->brc.hrd_buffer_size || !encoder_context->brc.hrd_initial_buffer_fullness) { encoder_context->brc.hrd_buffer_size = seq_param->bits_per_second << 1; encoder_context->brc.hrd_initial_buffer_fullness = seq_param->bits_per_second; } *seq_bits_per_second = seq_param->bits_per_second; return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_check_brc_vp8_sequence_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, unsigned int *seq_bits_per_second) { VAEncSequenceParameterBufferVP8 *seq_param = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer; unsigned int num_pframes_in_gop; if (!encoder_context->is_new_sequence) return VA_STATUS_SUCCESS; assert(seq_param); encoder_context->brc.num_iframes_in_gop = 1;// Always 1 encoder_context->brc.num_bframes_in_gop = 0;// No B frame if (seq_param->intra_period == 0) { // E.g. IPPP... (only one I frame in the stream) encoder_context->brc.gop_size = 30; // fake } else { encoder_context->brc.gop_size = seq_param->intra_period; } num_pframes_in_gop = encoder_context->brc.gop_size - 1; if (!encoder_context->brc.framerate[encoder_context->layer.num_layers - 1].num) { // for the highest layer encoder_context->brc.framerate[encoder_context->layer.num_layers - 1] = (struct intel_fraction) { 30, 1 }; encoder_context->brc.need_reset = 1; } if (num_pframes_in_gop != encoder_context->brc.num_pframes_in_gop) { encoder_context->brc.num_pframes_in_gop = num_pframes_in_gop; encoder_context->brc.need_reset = 1; } if (!encoder_context->brc.hrd_buffer_size || !encoder_context->brc.hrd_initial_buffer_fullness) { encoder_context->brc.hrd_buffer_size = seq_param->bits_per_second << 1; encoder_context->brc.hrd_initial_buffer_fullness = seq_param->bits_per_second; encoder_context->brc.need_reset = 1; } *seq_bits_per_second = seq_param->bits_per_second; return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_brc_hevc_sequence_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, unsigned int *seq_bits_per_second) { VAEncSequenceParameterBufferHEVC *seq_param = (VAEncSequenceParameterBufferHEVC*)encode_state->seq_param_ext->buffer; struct intel_fraction framerate; unsigned int gop_size, num_iframes_in_gop, num_pframes_in_gop, num_bframes_in_gop; if (!encoder_context->is_new_sequence) return VA_STATUS_SUCCESS; if (!seq_param) return VA_STATUS_ERROR_INVALID_PARAMETER; if (!seq_param->vui_time_scale || !seq_param->vui_num_units_in_tick) framerate = (struct intel_fraction) { 30, 1 }; else framerate = (struct intel_fraction) { seq_param->vui_time_scale, seq_param->vui_num_units_in_tick }; framerate = reduce_fraction(framerate); num_iframes_in_gop = 1; if (seq_param->intra_period == 0) { gop_size = -1; num_pframes_in_gop = -1; } else if (seq_param->intra_period == 1) { gop_size = 1; num_pframes_in_gop = 0; } else { gop_size = seq_param->intra_period; num_pframes_in_gop = (seq_param->intra_period + seq_param->ip_period - 1) / seq_param->ip_period - 1; } num_bframes_in_gop = gop_size - num_iframes_in_gop - num_pframes_in_gop; if (encoder_context->brc.framerate[0].num != framerate.num || encoder_context->brc.framerate[0].den != framerate.den) { encoder_context->brc.framerate[0] = framerate; encoder_context->brc.need_reset = 1; } if (encoder_context->brc.gop_size != gop_size || encoder_context->brc.num_iframes_in_gop != num_iframes_in_gop || encoder_context->brc.num_pframes_in_gop != num_pframes_in_gop || encoder_context->brc.num_bframes_in_gop != num_bframes_in_gop) { encoder_context->brc.gop_size = gop_size; encoder_context->brc.num_iframes_in_gop = num_iframes_in_gop; encoder_context->brc.num_pframes_in_gop = num_pframes_in_gop; encoder_context->brc.num_bframes_in_gop = num_bframes_in_gop; encoder_context->brc.need_reset = 1; } *seq_bits_per_second = seq_param->bits_per_second; return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_brc_vp9_sequence_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, unsigned int *seq_bits_per_second) { VAEncSequenceParameterBufferVP9 *seq_param = (VAEncSequenceParameterBufferVP9*)encode_state->seq_param_ext->buffer; unsigned int gop_size; if (!encoder_context->is_new_sequence) return VA_STATUS_SUCCESS; if (!seq_param) return VA_STATUS_ERROR_INVALID_PARAMETER; if (seq_param->intra_period == 0) gop_size = -1; // Dummy value (infinity). else gop_size = seq_param->intra_period; if (encoder_context->brc.gop_size != gop_size) { encoder_context->brc.gop_size = gop_size; encoder_context->brc.need_reset = 1; } *seq_bits_per_second = seq_param->bits_per_second; return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_brc_sequence_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context, unsigned int *seq_bits_per_second) { *seq_bits_per_second = 0; switch (encoder_context->codec) { case CODEC_H264: case CODEC_H264_MVC: return intel_encoder_check_brc_h264_sequence_parameter(ctx, encode_state, encoder_context, seq_bits_per_second); case CODEC_VP8: return intel_encoder_check_brc_vp8_sequence_parameter(ctx, encode_state, encoder_context, seq_bits_per_second); case CODEC_HEVC: return intel_encoder_check_brc_hevc_sequence_parameter(ctx, encode_state, encoder_context, seq_bits_per_second); case CODEC_VP9: return intel_encoder_check_brc_vp9_sequence_parameter(ctx, encode_state, encoder_context, seq_bits_per_second); default: // TODO: other codecs return VA_STATUS_SUCCESS; } } static void intel_encoder_check_rate_control_parameter(VADriverContextP ctx, struct intel_encoder_context *encoder_context, VAEncMiscParameterRateControl *misc, int *hl_bitrate_updated) { int temporal_id = 0; if (encoder_context->layer.num_layers >= 2) temporal_id = misc->rc_flags.bits.temporal_id; if (temporal_id >= encoder_context->layer.num_layers) return; if (misc->rc_flags.bits.reset) encoder_context->brc.need_reset = 1; if (encoder_context->brc.bits_per_second[temporal_id] != misc->bits_per_second) { encoder_context->brc.bits_per_second[temporal_id] = misc->bits_per_second; encoder_context->brc.need_reset = 1; } if (encoder_context->brc.mb_rate_control[temporal_id] != misc->rc_flags.bits.mb_rate_control) { encoder_context->brc.mb_rate_control[temporal_id] = misc->rc_flags.bits.mb_rate_control; encoder_context->brc.need_reset = 1; } if (encoder_context->brc.target_percentage[temporal_id] != misc->target_percentage) { encoder_context->brc.target_percentage[temporal_id] = misc->target_percentage; encoder_context->brc.need_reset = 1; } if (encoder_context->brc.window_size != misc->window_size || encoder_context->brc.initial_qp != misc->initial_qp || encoder_context->brc.min_qp != misc->min_qp) { encoder_context->brc.window_size = misc->window_size; encoder_context->brc.initial_qp = misc->initial_qp; encoder_context->brc.min_qp = misc->min_qp; encoder_context->brc.need_reset = 1; } if (temporal_id == encoder_context->layer.num_layers - 1) *hl_bitrate_updated = 1; } static void intel_encoder_check_hrd_parameter(VADriverContextP ctx, struct intel_encoder_context *encoder_context, VAEncMiscParameterHRD *misc) { if (encoder_context->brc.hrd_buffer_size != misc->buffer_size || encoder_context->brc.hrd_initial_buffer_fullness != misc->initial_buffer_fullness) { encoder_context->brc.hrd_buffer_size = misc->buffer_size; encoder_context->brc.hrd_initial_buffer_fullness = misc->initial_buffer_fullness; encoder_context->brc.need_reset = 1; } } static void intel_encoder_check_framerate_parameter(VADriverContextP ctx, struct intel_encoder_context *encoder_context, VAEncMiscParameterFrameRate *misc) { struct intel_fraction framerate; int temporal_id = 0; if (encoder_context->layer.num_layers >= 2) temporal_id = misc->framerate_flags.bits.temporal_id; if (temporal_id >= encoder_context->layer.num_layers) return; if (misc->framerate & 0xffff0000) framerate = (struct intel_fraction) { misc->framerate & 0xffff, misc->framerate >> 16 & 0xffff }; else framerate = (struct intel_fraction) { misc->framerate, 1 }; framerate = reduce_fraction(framerate); if (encoder_context->brc.framerate[temporal_id].num != framerate.num || encoder_context->brc.framerate[temporal_id].den != framerate.den) { encoder_context->brc.framerate[temporal_id] = framerate; encoder_context->brc.need_reset = 1; } } static void intel_encoder_check_roi_parameter(VADriverContextP ctx, struct intel_encoder_context *encoder_context, VAEncMiscParameterBufferROI *misc) { int i = 0; encoder_context->brc.num_roi = MIN(misc->num_roi, I965_MAX_NUM_ROI_REGIONS); encoder_context->brc.roi_max_delta_qp = misc->max_delta_qp; encoder_context->brc.roi_min_delta_qp = misc->min_delta_qp; encoder_context->brc.roi_value_is_qp_delta = 0; if (encoder_context->rate_control_mode != VA_RC_CQP) encoder_context->brc.roi_value_is_qp_delta = misc->roi_flags.bits.roi_value_is_qp_delta; for (i = 0; i < encoder_context->brc.num_roi; i++) { encoder_context->brc.roi[i].left = misc->roi->roi_rectangle.x; encoder_context->brc.roi[i].right = encoder_context->brc.roi[i].left + misc->roi->roi_rectangle.width; encoder_context->brc.roi[i].top = misc->roi->roi_rectangle.y; encoder_context->brc.roi[i].bottom = encoder_context->brc.roi[i].top + misc->roi->roi_rectangle.height; encoder_context->brc.roi[i].value = misc->roi->roi_value; } } static VAStatus intel_encoder_check_brc_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { VAStatus ret; VAEncMiscParameterBuffer *misc_param; int i, j; int hl_bitrate_updated = 0; // Indicate whether the bitrate for the highest level is changed in misc parameters unsigned int seq_bits_per_second = 0; if (encoder_context->rate_control_mode & (VA_RC_CBR | VA_RC_VBR)) { ret = intel_encoder_check_brc_sequence_parameter(ctx, encode_state, encoder_context, &seq_bits_per_second); if (ret) return ret; } for (i = 0; i < ARRAY_ELEMS(encode_state->misc_param); i++) { for (j = 0; j < ARRAY_ELEMS(encode_state->misc_param[0]); j++) { if (!encode_state->misc_param[i][j] || !encode_state->misc_param[i][j]->buffer) continue; misc_param = (VAEncMiscParameterBuffer *)encode_state->misc_param[i][j]->buffer; if (!(encoder_context->rate_control_mode & (VA_RC_CBR | VA_RC_VBR))) { if (misc_param->type != VAEncMiscParameterTypeROI) continue; } switch (misc_param->type) { case VAEncMiscParameterTypeFrameRate: intel_encoder_check_framerate_parameter(ctx, encoder_context, (VAEncMiscParameterFrameRate *)misc_param->data); break; case VAEncMiscParameterTypeRateControl: intel_encoder_check_rate_control_parameter(ctx, encoder_context, (VAEncMiscParameterRateControl *)misc_param->data, &hl_bitrate_updated); break; case VAEncMiscParameterTypeHRD: intel_encoder_check_hrd_parameter(ctx, encoder_context, (VAEncMiscParameterHRD *)misc_param->data); break; case VAEncMiscParameterTypeROI: intel_encoder_check_roi_parameter(ctx, encoder_context, (VAEncMiscParameterBufferROI *)misc_param->data); break; default: break; } } } if (!hl_bitrate_updated && seq_bits_per_second && encoder_context->brc.bits_per_second[encoder_context->layer.num_layers - 1] != seq_bits_per_second) { encoder_context->brc.bits_per_second[encoder_context->layer.num_layers - 1] = seq_bits_per_second; encoder_context->brc.need_reset = 1; } return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_temporal_layer_structure(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { VAEncMiscParameterBuffer* misc_param; VAEncMiscParameterTemporalLayerStructure *tls_paramter; unsigned int rate_control_mode = encoder_context->rate_control_mode; int i; if (!encoder_context->is_new_sequence) { if (encoder_context->layer.num_layers > 1) encoder_context->layer.curr_frame_layer_id = encoder_context->layer.frame_layer_ids[(encoder_context->num_frames_in_sequence - 1) % encoder_context->layer.size_frame_layer_ids]; else encoder_context->layer.curr_frame_layer_id = 0; return VA_STATUS_SUCCESS; } if (!(rate_control_mode & (VA_RC_CBR | VA_RC_VBR))) return VA_STATUS_SUCCESS; if (!encode_state->misc_param[VAEncMiscParameterTypeTemporalLayerStructure][0] || !encode_state->misc_param[VAEncMiscParameterTypeTemporalLayerStructure][0]->buffer) return VA_STATUS_SUCCESS; misc_param = (VAEncMiscParameterBuffer*)encode_state->misc_param[VAEncMiscParameterTypeTemporalLayerStructure][0]->buffer; tls_paramter = (VAEncMiscParameterTemporalLayerStructure *)misc_param->data; if (tls_paramter->number_of_layers <= 1) return VA_STATUS_SUCCESS; if (tls_paramter->number_of_layers > MAX_TEMPORAL_LAYERS) return VA_STATUS_ERROR_INVALID_PARAMETER; if (tls_paramter->periodicity > 32 || tls_paramter->periodicity <= 1) return VA_STATUS_ERROR_INVALID_PARAMETER; for (i = 0; i < tls_paramter->number_of_layers; i++) { if (!encode_state->misc_param[VAEncMiscParameterTypeRateControl][i] || !encode_state->misc_param[VAEncMiscParameterTypeRateControl][i]->buffer || !encode_state->misc_param[VAEncMiscParameterTypeFrameRate][i] || !encode_state->misc_param[VAEncMiscParameterTypeFrameRate][i]->buffer) { return VA_STATUS_ERROR_INVALID_PARAMETER; } } encoder_context->layer.size_frame_layer_ids = tls_paramter->periodicity; encoder_context->layer.num_layers = tls_paramter->number_of_layers; for (i = 0; i < encoder_context->layer.size_frame_layer_ids; i++) { if (tls_paramter->layer_id[i] >= tls_paramter->number_of_layers) return VA_STATUS_ERROR_INVALID_PARAMETER; encoder_context->layer.frame_layer_ids[i] = tls_paramter->layer_id[i]; } if (encoder_context->is_new_sequence) encoder_context->layer.curr_frame_layer_id = 0; else encoder_context->layer.curr_frame_layer_id = encoder_context->layer.frame_layer_ids[(encoder_context->num_frames_in_sequence - 1) % encoder_context->layer.size_frame_layer_ids]; return VA_STATUS_SUCCESS; } static VAStatus intel_encoder_check_misc_parameter(VADriverContextP ctx, VAProfile profile, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); VAStatus ret = VA_STATUS_SUCCESS; int min_width_height = I965_MIN_CODEC_ENC_RESOLUTION_WIDTH_HEIGHT; if (encoder_context->frame_width_in_pixel > 0 && encoder_context->frame_height_in_pixel > 0) { if (profile == VAProfileJPEGBaseline) min_width_height = 1; if (encoder_context->frame_width_in_pixel < min_width_height || encoder_context->frame_height_in_pixel < min_width_height) return VA_STATUS_ERROR_INVALID_PARAMETER; } if (encode_state->misc_param[VAEncMiscParameterTypeQualityLevel][0] && encode_state->misc_param[VAEncMiscParameterTypeQualityLevel][0]->buffer) { VAEncMiscParameterBuffer* pMiscParam = (VAEncMiscParameterBuffer*)encode_state->misc_param[VAEncMiscParameterTypeQualityLevel][0]->buffer; VAEncMiscParameterBufferQualityLevel* param_quality_level = (VAEncMiscParameterBufferQualityLevel*)pMiscParam->data; encoder_context->quality_level = param_quality_level->quality_level; if (encoder_context->quality_level == 0) { switch (profile) { case VAProfileH264ConstrainedBaseline: case VAProfileH264Main: case VAProfileH264High: case VAProfileH264MultiviewHigh: case VAProfileH264StereoHigh: if (IS_GEN9(i965->intel.device_info) || IS_GEN10(i965->intel.device_info)) encoder_context->quality_level = ENCODER_DEFAULT_QUALITY_AVC; break; case VAProfileHEVCMain: case VAProfileHEVCMain10: encoder_context->quality_level = ENCODER_DEFAULT_QUALITY_HEVC; break; default: encoder_context->quality_level = ENCODER_DEFAULT_QUALITY; break; } } else if (encoder_context->quality_level > encoder_context->quality_range) { i965_log_info(ctx, "VAEncMiscParameterBufferQualityLevel.quality_level (%d) out of range (max %d).\n", encoder_context->quality_level, encoder_context->quality_range); ret = VA_STATUS_ERROR_INVALID_PARAMETER; goto out; } } ret = intel_encoder_check_temporal_layer_structure(ctx, encode_state, encoder_context); if (ret) goto out; ret = intel_encoder_check_brc_parameter(ctx, encode_state, encoder_context); out: return ret; } static VAStatus intel_encoder_check_avc_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct object_surface *obj_surface; struct object_buffer *obj_buffer; VAEncPictureParameterBufferH264 *pic_param = (VAEncPictureParameterBufferH264 *)encode_state->pic_param_ext->buffer; VAEncSequenceParameterBufferH264 *seq_param = (VAEncSequenceParameterBufferH264 *)encode_state->seq_param_ext->buffer; int i; if (!seq_param) goto error; if (seq_param->level_idc != encoder_context->codec_level && !i965_avc_level_is_valid(seq_param->level_idc)) { i965_log_info(ctx, "VAEncSequenceParameterBufferH264.level_idc (%d) does not appear to be valid.\n", seq_param->level_idc); encoder_context->codec_level = seq_param->level_idc; // Only print this the first time we see it, and continue anyway - this could be a correct future // value or an unknown extension. } if (pic_param->CurrPic.flags & VA_PICTURE_H264_INVALID) { i965_log_info(ctx, "VAEncPictureParameterBufferH264.CurrPic.flags (%#x) is invalid.\n", pic_param->CurrPic.flags); goto error; } obj_surface = SURFACE(pic_param->CurrPic.picture_id); if (!obj_surface) { i965_log_info(ctx, "VAEncPictureParameterBufferH264.CurrPic.picture_id (%#x) is not a valid surface.\n", pic_param->CurrPic.picture_id); goto error; } encode_state->reconstructed_object = obj_surface; obj_buffer = BUFFER(pic_param->coded_buf); if (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo) { i965_log_info(ctx, "VAEncPictureParameterBufferH264.coded_buf (%#x) is not a valid buffer.\n", pic_param->coded_buf); goto error; } if (encode_state->num_slice_params_ext > encoder_context->max_slice_or_seg_num) { i965_log_info(ctx, "Too many slices in picture submission: %d, max supported is %d.\n", encode_state->num_slice_params_ext, encoder_context->max_slice_or_seg_num); goto error; } encode_state->coded_buf_object = obj_buffer; for (i = 0; i < 16; i++) { if (pic_param->ReferenceFrames[i].flags & VA_PICTURE_H264_INVALID || pic_param->ReferenceFrames[i].picture_id == VA_INVALID_SURFACE) break; else { obj_surface = SURFACE(pic_param->ReferenceFrames[i].picture_id); if (!obj_surface || !obj_surface->bo) { i965_log_info(ctx, "VAEncPictureParameterBufferH264.ReferenceFrames[%d].picture_id (%#x)" " is not a valid surface.\n", i, pic_param->ReferenceFrames[i].picture_id); goto error; } encode_state->reference_objects[i] = obj_surface; } } for (; i < 16; i++) encode_state->reference_objects[i] = NULL; /* * A sequence consists of an IDR unit, followed by zero or more non-IDR unit, but not including any * subsequent IDR unit, so idr_pic_flag can indicate the current frame is the start of a new * sequnce */ encoder_context->is_new_sequence = pic_param->pic_fields.bits.idr_pic_flag; if (encoder_context->is_new_sequence) { encoder_context->num_frames_in_sequence = 0; encoder_context->frame_width_in_pixel = seq_param->picture_width_in_mbs * 16; encoder_context->frame_height_in_pixel = seq_param->picture_height_in_mbs * 16; } return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_pre_encoder_check_avc_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct object_surface *obj_surface = NULL; VAStatsStatisticsParameterH264 *stat_param_h264 = NULL; VAStatsStatisticsParameter*stat_param = NULL; if (!encode_state->stat_param_ext) goto error; stat_param_h264 = (VAStatsStatisticsParameterH264 *) encode_state->stat_param_ext->buffer; stat_param = (VAStatsStatisticsParameter *)(&stat_param_h264->stats_params); if (stat_param->input.flags == VA_PICTURE_STATS_INVALID) goto error; obj_surface = SURFACE(encoder_context->input_yuv_surface); if (!obj_surface) goto error; #if 0 /* FeiPreEncFixme: Since the driver is doing internal CSC for non NV12 input surfaces, this check may fail here */ /* Make sure the same input yuv has been provided in vaBeginPicture() * and VAStatsStatisticsParameter */ if (obj_surface != SURFACE(stat_param->input.picture_id)) goto error; #endif /* There is no reconstructed object in preenc. Here we just assigning * the input yuv object to reconstructed object pointer inorder * to use the same encode code path later on */ encode_state->reconstructed_object = obj_surface; encoder_context->frame_width_in_pixel = obj_surface->orig_width; encoder_context->frame_height_in_pixel = obj_surface->orig_height; /* PreEnc only supports maxium of 1 past and 1 future reference */ if (stat_param->num_past_references > 1 || stat_param->num_future_references > 1) goto error; return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_check_mpeg2_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); VAEncPictureParameterBufferMPEG2 *pic_param = (VAEncPictureParameterBufferMPEG2 *)encode_state->pic_param_ext->buffer; VAEncSequenceParameterBufferMPEG2 *seq_param = NULL; struct object_surface *obj_surface; struct object_buffer *obj_buffer; int i = 0; if (encode_state->seq_param_ext && encode_state->seq_param_ext->buffer) seq_param = (VAEncSequenceParameterBufferMPEG2 *)encode_state->seq_param_ext->buffer; obj_surface = SURFACE(pic_param->reconstructed_picture); assert(obj_surface); /* It is possible the store buffer isn't allocated yet */ if (!obj_surface) goto error; encode_state->reconstructed_object = obj_surface; obj_buffer = BUFFER(pic_param->coded_buf); assert(obj_buffer && obj_buffer->buffer_store && obj_buffer->buffer_store->bo); if (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo) goto error; encode_state->coded_buf_object = obj_buffer; if (pic_param->picture_type == VAEncPictureTypeIntra) { } else if (pic_param->picture_type == VAEncPictureTypePredictive) { assert(pic_param->forward_reference_picture != VA_INVALID_SURFACE); obj_surface = SURFACE(pic_param->forward_reference_picture); assert(obj_surface && obj_surface->bo); if (!obj_surface || !obj_surface->bo) goto error; encode_state->reference_objects[i++] = obj_surface; } else if (pic_param->picture_type == VAEncPictureTypeBidirectional) { assert(pic_param->forward_reference_picture != VA_INVALID_SURFACE); obj_surface = SURFACE(pic_param->forward_reference_picture); assert(obj_surface && obj_surface->bo); if (!obj_surface || !obj_surface->bo) goto error; encode_state->reference_objects[i++] = obj_surface; assert(pic_param->backward_reference_picture != VA_INVALID_SURFACE); obj_surface = SURFACE(pic_param->backward_reference_picture); assert(obj_surface && obj_surface->bo); if (!obj_surface || !obj_surface->bo) goto error; encode_state->reference_objects[i++] = obj_surface; } else goto error; for (; i < 16; i++) encode_state->reference_objects[i] = NULL; if (seq_param) { encoder_context->frame_width_in_pixel = seq_param->picture_width; encoder_context->frame_height_in_pixel = seq_param->picture_height; } return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_check_jpeg_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct object_buffer *obj_buffer; VAEncPictureParameterBufferJPEG *pic_param = (VAEncPictureParameterBufferJPEG *)encode_state->pic_param_ext->buffer; assert(!(pic_param->pic_flags.bits.profile)); //Baseline profile is 0. obj_buffer = BUFFER(pic_param->coded_buf); assert(obj_buffer && obj_buffer->buffer_store && obj_buffer->buffer_store->bo); if (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo) goto error; encode_state->coded_buf_object = obj_buffer; encoder_context->frame_width_in_pixel = pic_param->picture_width; encoder_context->frame_height_in_pixel = pic_param->picture_height; return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_check_vp8_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer; VAEncSequenceParameterBufferVP8 *seq_param = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer; struct object_surface *obj_surface; struct object_buffer *obj_buffer; int i = 0; int is_key_frame = !pic_param->pic_flags.bits.frame_type; obj_surface = SURFACE(pic_param->reconstructed_frame); if (!obj_surface) goto error; encode_state->reconstructed_object = obj_surface; obj_buffer = BUFFER(pic_param->coded_buf); if (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo) goto error; encode_state->coded_buf_object = obj_buffer; if (!is_key_frame) { if (!pic_param->ref_flags.bits.no_ref_last) { obj_surface = SURFACE(pic_param->ref_last_frame); if (!obj_surface || !obj_surface->bo) goto error; encode_state->reference_objects[i++] = obj_surface; } else { encode_state->reference_objects[i++] = NULL; } if (!pic_param->ref_flags.bits.no_ref_gf) { obj_surface = SURFACE(pic_param->ref_gf_frame); if (!obj_surface || !obj_surface->bo) goto error; encode_state->reference_objects[i++] = obj_surface; } else { encode_state->reference_objects[i++] = NULL; } if (!pic_param->ref_flags.bits.no_ref_arf) { obj_surface = SURFACE(pic_param->ref_arf_frame); if (!obj_surface || !obj_surface->bo) goto error; encode_state->reference_objects[i++] = obj_surface; } else { encode_state->reference_objects[i++] = NULL; } } for (; i < 16; i++) encode_state->reference_objects[i] = NULL; encoder_context->is_new_sequence = (is_key_frame && seq_param); if (encoder_context->is_new_sequence) { encoder_context->num_frames_in_sequence = 0; encoder_context->frame_width_in_pixel = seq_param->frame_width; encoder_context->frame_height_in_pixel = seq_param->frame_height; } return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_check_hevc_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct object_surface *obj_surface; struct object_buffer *obj_buffer; VAEncPictureParameterBufferHEVC *pic_param = (VAEncPictureParameterBufferHEVC *)encode_state->pic_param_ext->buffer; VAEncSliceParameterBufferHEVC *slice_param; VAEncSequenceParameterBufferHEVC *seq_param; int i; seq_param = NULL; if (encode_state->seq_param_ext && encode_state->seq_param_ext->buffer) seq_param = (VAEncSequenceParameterBufferHEVC *)(encode_state->seq_param_ext->buffer); if (pic_param->decoded_curr_pic.flags & VA_PICTURE_HEVC_INVALID) { i965_log_info(ctx, "VAEncPictureParameterBufferHEVC.decoded_curr_pic.flags (%#x) is invalid.\n", pic_param->decoded_curr_pic.flags); goto error; } obj_surface = SURFACE(pic_param->decoded_curr_pic.picture_id); if (!obj_surface) { i965_log_info(ctx, "VAEncPictureParameterBufferHEVC.decoded_curr_pic.picture_id (%#x) is not a valid surface.\n", pic_param->decoded_curr_pic.picture_id); goto error; } encode_state->reconstructed_object = obj_surface; obj_buffer = BUFFER(pic_param->coded_buf); if (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo) { i965_log_info(ctx, "VAEncPictureParameterBufferHEVC.coded_buf (%#x) is not a valid buffer.\n", pic_param->coded_buf); goto error; } if (encode_state->num_slice_params_ext > encoder_context->max_slice_or_seg_num) { i965_log_info(ctx, "Too many slices in picture submission: %d, max supported is %d.\n", encode_state->num_slice_params_ext, encoder_context->max_slice_or_seg_num); goto error; } encode_state->coded_buf_object = obj_buffer; for (i = 0; i < 15; i++) { if (pic_param->reference_frames[i].flags & VA_PICTURE_HEVC_INVALID || pic_param->reference_frames[i].picture_id == VA_INVALID_SURFACE) break; else { obj_surface = SURFACE(pic_param->reference_frames[i].picture_id); if (!obj_surface || !obj_surface->bo) { i965_log_info(ctx, "VAEncPictureParameterBufferHEVC.reference_frames[%d].picture_id (%#x)" " is not a valid surface.\n", i, pic_param->reference_frames[i].picture_id); goto error; } encode_state->reference_objects[i] = obj_surface; } } for (; i < 15; i++) encode_state->reference_objects[i] = NULL; for (i = 0; i < encode_state->num_slice_params_ext; i++) { slice_param = (VAEncSliceParameterBufferHEVC *)encode_state->slice_params_ext[i]->buffer; if (slice_param->slice_type != HEVC_SLICE_I && slice_param->slice_type != HEVC_SLICE_P && slice_param->slice_type != HEVC_SLICE_B) goto error; /* TODO: add more check here */ } encoder_context->is_new_sequence = (pic_param->pic_fields.bits.idr_pic_flag && seq_param); if (encoder_context->is_new_sequence) { encoder_context->num_frames_in_sequence = 0; encoder_context->frame_width_in_pixel = seq_param->pic_width_in_luma_samples; encoder_context->frame_height_in_pixel = seq_param->pic_height_in_luma_samples; } return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_check_vp9_parameter(VADriverContextP ctx, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { struct i965_driver_data *i965 = i965_driver_data(ctx); VAEncPictureParameterBufferVP9 *pic_param; VAEncSequenceParameterBufferVP9 *seq_param; struct object_surface *obj_surface; struct object_buffer *obj_buffer; int i = 0; int is_key_frame = 0; int index; if (encode_state->pic_param_ext == NULL || encode_state->pic_param_ext->buffer == NULL) return VA_STATUS_ERROR_INVALID_PARAMETER; seq_param = NULL; if (encode_state->seq_param_ext && encode_state->seq_param_ext->buffer) seq_param = (VAEncSequenceParameterBufferVP9 *)(encode_state->seq_param_ext->buffer); pic_param = (VAEncPictureParameterBufferVP9 *)encode_state->pic_param_ext->buffer; obj_surface = SURFACE(pic_param->reconstructed_frame); if (!obj_surface) goto error; encode_state->reconstructed_object = obj_surface; obj_buffer = BUFFER(pic_param->coded_buf); if (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo) goto error; encode_state->coded_buf_object = obj_buffer; is_key_frame = !pic_param->pic_flags.bits.frame_type; if (!is_key_frame && !pic_param->pic_flags.bits.intra_only) { /* slot 0 is for last reference frame */ index = pic_param->ref_flags.bits.ref_last_idx; obj_surface = SURFACE(pic_param->reference_frames[index]); if (obj_surface && obj_surface->bo) encode_state->reference_objects[i++] = obj_surface; else encode_state->reference_objects[i++] = NULL; /* slot 1 is for golden reference frame */ index = pic_param->ref_flags.bits.ref_gf_idx; obj_surface = SURFACE(pic_param->reference_frames[index]); if (obj_surface && obj_surface->bo) encode_state->reference_objects[i++] = obj_surface; else encode_state->reference_objects[i++] = NULL; /* slot 2 is alt reference frame */ index = pic_param->ref_flags.bits.ref_arf_idx; obj_surface = SURFACE(pic_param->reference_frames[index]); if (obj_surface && obj_surface->bo) encode_state->reference_objects[i++] = obj_surface; else encode_state->reference_objects[i++] = NULL; } for (; i < 16; i++) encode_state->reference_objects[i] = NULL; encoder_context->is_new_sequence = (is_key_frame && seq_param); encoder_context->frame_width_in_pixel = pic_param->frame_width_src; encoder_context->frame_height_in_pixel = pic_param->frame_height_src; return VA_STATUS_SUCCESS; error: return VA_STATUS_ERROR_INVALID_PARAMETER; } static VAStatus intel_encoder_sanity_check_input(VADriverContextP ctx, VAProfile profile, struct encode_state *encode_state, struct intel_encoder_context *encoder_context) { VAStatus vaStatus; switch (profile) { case VAProfileH264ConstrainedBaseline: case VAProfileH264Main: case VAProfileH264High: case VAProfileH264MultiviewHigh: case VAProfileH264StereoHigh: { if (!encoder_context->preenc_enabled) { vaStatus = intel_encoder_check_avc_parameter(ctx, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context); break; } else { vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_pre_encoder_check_avc_parameter(ctx, encode_state, encoder_context); goto out; } } case VAProfileMPEG2Simple: case VAProfileMPEG2Main: { vaStatus = intel_encoder_check_mpeg2_parameter(ctx, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context); break; } case VAProfileJPEGBaseline: { vaStatus = intel_encoder_check_jpeg_parameter(ctx, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_encoder_check_jpeg_yuv_surface(ctx, profile, encode_state, encoder_context); break; } case VAProfileVP8Version0_3: { vaStatus = intel_encoder_check_vp8_parameter(ctx, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context); break; } case VAProfileHEVCMain: case VAProfileHEVCMain10: { vaStatus = intel_encoder_check_hevc_parameter(ctx, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context); break; } case VAProfileVP9Profile0: { vaStatus = intel_encoder_check_vp9_parameter(ctx, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) goto out; vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context); break; } default: vaStatus = VA_STATUS_ERROR_UNSUPPORTED_PROFILE; break; } if (vaStatus == VA_STATUS_SUCCESS) vaStatus = intel_encoder_check_misc_parameter(ctx, profile, encode_state, encoder_context); out: return vaStatus; } static VAStatus intel_encoder_end_picture(VADriverContextP ctx, VAProfile profile, union codec_state *codec_state, struct hw_context *hw_context) { struct intel_encoder_context *encoder_context = (struct intel_encoder_context *)hw_context; struct encode_state *encode_state = &codec_state->encode; VAStatus vaStatus; vaStatus = intel_encoder_sanity_check_input(ctx, profile, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) return vaStatus; encoder_context->mfc_brc_prepare(encode_state, encoder_context); /* VME or PAK stages are separately invoked if middleware configured the corresponding * FEI modes through confgiruation attributes. On the other hand, ENC_PAK mode * will invoke both VME and PAK similar to the non fei use case. * PreEnc always invoke the VME */ if (encoder_context->fei_enabled || encoder_context->preenc_enabled) { if ((encoder_context->fei_function_mode == VA_FEI_FUNCTION_ENC) || (encoder_context->preenc_enabled)) { if ((encoder_context->vme_context && encoder_context->vme_pipeline)) return encoder_context->vme_pipeline(ctx, profile, encode_state, encoder_context); } else if (encoder_context->fei_function_mode == VA_FEI_FUNCTION_PAK) { if ((encoder_context->mfc_context && encoder_context->mfc_pipeline)) return encoder_context->mfc_pipeline(ctx, profile, encode_state, encoder_context); } /* Setting ENC and PAK as ENC|PAK is invalid */ assert(encoder_context->fei_function_mode != (VA_FEI_FUNCTION_ENC | VA_FEI_FUNCTION_PAK)); } if ((encoder_context->vme_context && encoder_context->vme_pipeline)) { vaStatus = encoder_context->vme_pipeline(ctx, profile, encode_state, encoder_context); if (vaStatus != VA_STATUS_SUCCESS) return vaStatus; } assert(encoder_context->mfc_pipeline != NULL); encoder_context->mfc_pipeline(ctx, profile, encode_state, encoder_context); encoder_context->num_frames_in_sequence++; encoder_context->brc.need_reset = 0; /* * ROI is only available for the current frame, see the comment * for VAEncROI in va.h */ encoder_context->brc.num_roi = 0; return VA_STATUS_SUCCESS; } static void intel_encoder_context_destroy(void *hw_context) { struct intel_encoder_context *encoder_context = (struct intel_encoder_context *)hw_context; encoder_context->mfc_context_destroy(encoder_context->mfc_context); if (encoder_context->vme_context_destroy && encoder_context->vme_context) encoder_context->vme_context_destroy(encoder_context->vme_context); if (encoder_context->enc_priv_state) { free(encoder_context->enc_priv_state); encoder_context->enc_priv_state = NULL; } if (encoder_context->is_tmp_id) { assert(encoder_context->input_yuv_surface != VA_INVALID_SURFACE); i965_DestroySurfaces(encoder_context->ctx, &encoder_context->input_yuv_surface, 1); encoder_context->is_tmp_id = 0; } intel_batchbuffer_free(encoder_context->base.batch); free(encoder_context); } static VAStatus intel_encoder_get_status(VADriverContextP ctx, struct hw_context *hw_context, void *buffer) { struct intel_encoder_context *encoder_context = (struct intel_encoder_context *)hw_context; struct i965_coded_buffer_segment *coded_buffer_segment = (struct i965_coded_buffer_segment *)buffer; if (encoder_context->get_status) return encoder_context->get_status(ctx, encoder_context, coded_buffer_segment); return VA_STATUS_ERROR_UNIMPLEMENTED; } typedef Bool(* hw_init_func)(VADriverContextP, struct intel_encoder_context *); static struct hw_context * intel_enc_hw_context_init(VADriverContextP ctx, struct object_config *obj_config, hw_init_func vme_context_init, hw_init_func mfc_context_init) { struct i965_driver_data *i965 = i965_driver_data(ctx); struct intel_driver_data *intel = intel_driver_data(ctx); struct intel_encoder_context *encoder_context = calloc(1, sizeof(struct intel_encoder_context)); int i; assert(encoder_context); encoder_context->base.destroy = intel_encoder_context_destroy; encoder_context->base.run = intel_encoder_end_picture; encoder_context->base.get_status = intel_encoder_get_status; encoder_context->base.batch = intel_batchbuffer_new(intel, I915_EXEC_RENDER, 0); encoder_context->input_yuv_surface = VA_INVALID_SURFACE; encoder_context->is_tmp_id = 0; encoder_context->low_power_mode = 0; encoder_context->rate_control_mode = VA_RC_NONE; encoder_context->quality_level = ENCODER_DEFAULT_QUALITY; encoder_context->quality_range = 1; encoder_context->layer.num_layers = 1; encoder_context->max_slice_or_seg_num = 1; encoder_context->ctx = ctx; if (obj_config->entrypoint == VAEntrypointEncSliceLP) encoder_context->low_power_mode = 1; switch (obj_config->profile) { case VAProfileMPEG2Simple: case VAProfileMPEG2Main: encoder_context->codec = CODEC_MPEG2; break; case VAProfileH264ConstrainedBaseline: case VAProfileH264Main: case VAProfileH264High: encoder_context->codec = CODEC_H264; if (obj_config->entrypoint == VAEntrypointEncSliceLP) encoder_context->quality_range = ENCODER_LP_QUALITY_RANGE; else if (IS_GEN9(i965->intel.device_info) || IS_GEN10(i965->intel.device_info)) { encoder_context->quality_level = ENCODER_DEFAULT_QUALITY_AVC; encoder_context->quality_range = ENCODER_QUALITY_RANGE_AVC; } else encoder_context->quality_range = ENCODER_QUALITY_RANGE; if (obj_config->entrypoint == VAEntrypointFEI) { encoder_context->fei_enabled = 1; /* check which attribute has been configured for FEI, this is * required for VME/PAK disable or enable as per user request */ for (i = 0; i < obj_config->num_attribs; i++) { if (obj_config->attrib_list[i].type == VAConfigAttribFEIFunctionType) encoder_context->fei_function_mode = obj_config->attrib_list[i].value; } } if (obj_config->entrypoint == VAEntrypointStats) encoder_context->preenc_enabled = 1; break; case VAProfileH264StereoHigh: case VAProfileH264MultiviewHigh: if (IS_GEN9(i965->intel.device_info) || IS_GEN10(i965->intel.device_info)) { encoder_context->quality_level = ENCODER_DEFAULT_QUALITY_AVC; encoder_context->quality_range = ENCODER_QUALITY_RANGE_AVC; } encoder_context->codec = CODEC_H264_MVC; break; case VAProfileJPEGBaseline: encoder_context->codec = CODEC_JPEG; break; case VAProfileVP8Version0_3: encoder_context->codec = CODEC_VP8; encoder_context->quality_range = ENCODER_QUALITY_RANGE; break; case VAProfileHEVCMain: case VAProfileHEVCMain10: encoder_context->codec = CODEC_HEVC; encoder_context->quality_level = ENCODER_DEFAULT_QUALITY_HEVC; encoder_context->quality_range = ENCODER_QUALITY_RANGE_HEVC; encoder_context->max_slice_or_seg_num = I965_MAX_NUM_SLICE; break; case VAProfileVP9Profile0: encoder_context->codec = CODEC_VP9; if (obj_config->entrypoint == VAEntrypointEncSliceLP) { encoder_context->quality_level = ENCODER_DEFAULT_QUALITY_VP9; encoder_context->quality_range = ENCODER_QUALITY_RANGE_VP9; } break; default: /* Never get here */ assert(0); break; } for (i = 0; i < obj_config->num_attribs; i++) { if (obj_config->attrib_list[i].type == VAConfigAttribRateControl) { encoder_context->rate_control_mode = obj_config->attrib_list[i].value; if (encoder_context->codec == CODEC_MPEG2 && encoder_context->rate_control_mode & VA_RC_CBR) { WARN_ONCE("Don't support CBR for MPEG-2 encoding\n"); encoder_context->rate_control_mode &= ~VA_RC_CBR; } } if (obj_config->attrib_list[i].type == VAConfigAttribEncROI) { if (encoder_context->codec == CODEC_H264) encoder_context->context_roi = 1; } if (obj_config->attrib_list[i].type == VAConfigAttribEncMaxSlices) { if (encoder_context->codec == CODEC_H264 || encoder_context->codec == CODEC_HEVC) encoder_context->max_slice_or_seg_num = obj_config->attrib_list[i].value; } } if (vme_context_init) { vme_context_init(ctx, encoder_context); assert(!encoder_context->vme_context || (encoder_context->vme_context_destroy && encoder_context->vme_pipeline)); } mfc_context_init(ctx, encoder_context); assert(encoder_context->mfc_context); assert(encoder_context->mfc_context_destroy); assert(encoder_context->mfc_pipeline); return (struct hw_context *)encoder_context; } struct hw_context * gen6_enc_hw_context_init(VADriverContextP ctx, struct object_config *obj_config) { return intel_enc_hw_context_init(ctx, obj_config, gen6_vme_context_init, gen6_mfc_context_init); } struct hw_context * gen7_enc_hw_context_init(VADriverContextP ctx, struct object_config *obj_config) { return intel_enc_hw_context_init(ctx, obj_config, gen7_vme_context_init, gen7_mfc_context_init); } struct hw_context * gen75_enc_hw_context_init(VADriverContextP ctx, struct object_config *obj_config) { return intel_enc_hw_context_init(ctx, obj_config, gen75_vme_context_init, gen75_mfc_context_init); } struct hw_context * gen8_enc_hw_context_init(VADriverContextP ctx, struct object_config *obj_config) { return intel_enc_hw_context_init(ctx, obj_config, gen8_vme_context_init, gen8_mfc_context_init); } struct hw_context * gen9_enc_hw_context_init(VADriverContextP ctx, struct object_config *obj_config) { return intel_enc_hw_context_init(ctx, obj_config, gen9_vme_context_init, gen9_mfc_context_init); }