#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;
+ int i, j;
if (obj_surface->border_cleared)
return VA_STATUS_SUCCESS;
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[0] = obj_surface->height;
vstride[1] = obj_surface->height / 2;
} else {
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) {
if (obj_surface->fourcc == VA_FOURCC_NV12 ||
(VAProfileHEVCMain10 == profile &&
- obj_surface->fourcc == VA_FOURCC_P010)) {
+ obj_surface->fourcc == VA_FOURCC_P010)) {
unsigned int tiling = 0, swizzle = 0;
dri_bo_get_tiling(obj_surface->bo, &tiling, &swizzle);
}
}
+ 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,
- VA_RT_FORMAT_YUV420,
+ 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, VA_FOURCC_NV12, SUBSAMPLE_YUV420);
-
+ 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;
static VAStatus
intel_encoder_check_jpeg_yuv_surface(VADriverContextP ctx,
- VAProfile profile,
- struct encode_state *encode_state,
- struct intel_encoder_context *encoder_context)
+ 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;
+ int format = 0, fourcc = 0, subsample = 0;
/* releae the temporary surface */
if (encoder_context->is_tmp_id) {
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) ) {
+ 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;
src_surface.type = I965_SURFACE_TYPE_SURFACE;
src_surface.flags = I965_SURFACE_FLAG_FRAME;
- switch( obj_surface->fourcc) {
+ switch (obj_surface->fourcc) {
- case VA_FOURCC_YUY2:
- fourcc = VA_FOURCC_YUY2;
- format = VA_RT_FORMAT_YUV422;
- subsample = SUBSAMPLE_YUV422H;
- break;
+ 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_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_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_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;
+ 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;
+ 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,
//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){
+ if (obj_surface->fourcc != VA_FOURCC_Y800) {
status = i965_image_processing(ctx,
- &src_surface,
- &rect,
- &dst_surface,
- &rect);
+ &src_surface,
+ &rect,
+ &dst_surface,
+ &rect);
assert(status == 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)
+ 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;
- unsigned int bits_per_second, framerate_per_100s;
if (!encoder_context->is_new_sequence)
return VA_STATUS_SUCCESS;
assert(seq_param);
- bits_per_second = seq_param->bits_per_second; // for the highest layer
- if (!seq_param->num_units_in_tick || !seq_param->time_scale)
- framerate_per_100s = 3000;
- else
- framerate_per_100s = seq_param->time_scale * 100 / (2 * seq_param->num_units_in_tick); // for the highest layer
+ 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->ip_period == 0)
goto error;
- encoder_context->brc.gop_size = (unsigned int)(framerate_per_100s / 100.0 + 0.5); // fake
+ 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...
if (num_pframes_in_gop != encoder_context->brc.num_pframes_in_gop ||
num_bframes_in_gop != encoder_context->brc.num_bframes_in_gop ||
- bits_per_second != encoder_context->brc.bits_per_second[encoder_context->layer.num_layers - 1] ||
- framerate_per_100s != encoder_context->brc.framerate_per_100s[encoder_context->layer.num_layers - 1]) {
+ 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.bits_per_second[encoder_context->layer.num_layers - 1] = bits_per_second;
- encoder_context->brc.framerate_per_100s[encoder_context->layer.num_layers - 1] = framerate_per_100s;
+ encoder_context->brc.framerate[encoder_context->layer.num_layers - 1] = framerate;
encoder_context->brc.need_reset = 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:
static VAStatus
intel_encoder_check_brc_vp8_sequence_parameter(VADriverContextP ctx,
struct encode_state *encode_state,
- struct intel_encoder_context *encoder_context)
+ 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, bits_per_second;
+ unsigned int num_pframes_in_gop;
if (!encoder_context->is_new_sequence)
return VA_STATUS_SUCCESS;
}
num_pframes_in_gop = encoder_context->brc.gop_size - 1;
- bits_per_second = seq_param->bits_per_second; // for the highest layer
- if (!encoder_context->brc.framerate_per_100s[encoder_context->layer.num_layers - 1]) {
- encoder_context->brc.framerate_per_100s[encoder_context->layer.num_layers - 1] = 3000; // for the highest layer
+ 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 ||
- bits_per_second != encoder_context->brc.bits_per_second[encoder_context->layer.num_layers - 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.bits_per_second[encoder_context->layer.num_layers - 1] = bits_per_second;
encoder_context->brc.need_reset = 1;
}
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)
+ struct intel_encoder_context *encoder_context,
+ unsigned int *seq_bits_per_second)
{
- if (encoder_context->codec == CODEC_H264 ||
- encoder_context->codec == CODEC_H264_MVC)
- return intel_encoder_check_brc_h264_sequence_parameter(ctx, encode_state, encoder_context);
+ *seq_bits_per_second = 0;
- if (encoder_context->codec == CODEC_VP8)
- return intel_encoder_check_brc_vp8_sequence_parameter(ctx, encode_state, encoder_context);
+ 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);
- // TODO: other codecs
- return VA_STATUS_SUCCESS;
+ 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)
+ VAEncMiscParameterRateControl *misc,
+ int *hl_bitrate_updated)
{
int temporal_id = 0;
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
struct intel_encoder_context *encoder_context,
VAEncMiscParameterFrameRate *misc)
{
- int framerate_per_100s;
+ struct intel_fraction framerate;
int temporal_id = 0;
if (encoder_context->layer.num_layers >= 2)
return;
if (misc->framerate & 0xffff0000)
- framerate_per_100s = (misc->framerate & 0xffff) * 100 / ((misc->framerate >> 16) & 0xffff);
+ framerate = (struct intel_fraction) {
+ misc->framerate & 0xffff, misc->framerate >> 16 & 0xffff
+ };
else
- framerate_per_100s = misc->framerate * 100;
-
- if (encoder_context->brc.framerate_per_100s[temporal_id] != framerate_per_100s) {
- encoder_context->brc.framerate_per_100s[temporal_id] = framerate_per_100s;
+ 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;
}
}
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)))
- return VA_STATUS_SUCCESS;
-
- ret = intel_encoder_check_brc_sequence_parameter(ctx, encode_state, encoder_context);
+ 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;
+ 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++) {
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,
case VAEncMiscParameterTypeRateControl:
intel_encoder_check_rate_control_parameter(ctx,
encoder_context,
- (VAEncMiscParameterRateControl *)misc_param->data);
+ (VAEncMiscParameterRateControl *)misc_param->data,
+ &hl_bitrate_updated);
break;
case VAEncMiscParameterTypeHRD:
}
}
+ 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_misc_parameter(VADriverContextP ctx,
- struct encode_state *encode_state,
- struct intel_encoder_context *encoder_context)
+ 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) {
VAEncMiscParameterBufferQualityLevel* param_quality_level = (VAEncMiscParameterBufferQualityLevel*)pMiscParam->data;
encoder_context->quality_level = param_quality_level->quality_level;
- if (encoder_context->quality_level == 0)
- encoder_context->quality_level = ENCODER_DEFAULT_QUALITY;
- else if (encoder_context->quality_level > encoder_context->quality_range) {
+ 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;
}
struct intel_encoder_context *encoder_context)
{
struct i965_driver_data *i965 = i965_driver_data(ctx);
- struct object_surface *obj_surface;
+ 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;
- assert(!(pic_param->CurrPic.flags & VA_PICTURE_H264_INVALID));
+ 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)
+ 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);
- assert(obj_surface); /* It is possible the store buffer isn't allocated yet */
-
- if (!obj_surface)
+ 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);
- assert(obj_buffer && obj_buffer->buffer_store && obj_buffer->buffer_store->bo);
+ 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 (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo)
+ 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;
break;
else {
obj_surface = SURFACE(pic_param->ReferenceFrames[i].picture_id);
- assert(obj_surface);
-
- if (!obj_surface)
+ 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;
-
- if (obj_surface->bo)
- encode_state->reference_objects[i] = obj_surface;
- else
- encode_state->reference_objects[i] = NULL; /* FIXME: Warning or Error ??? */
+ }
+ encode_state->reference_objects[i] = obj_surface;
}
}
- for ( ; i < 16; i++)
+ for (; i < 16; i++)
encode_state->reference_objects[i] = NULL;
/*
}
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;
- struct object_surface *obj_surface;
+ 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;
+
+ 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);
goto error;
encode_state->reference_objects[i++] = obj_surface;
- } else
+ } else
goto error;
- for ( ; i < 16; i++)
+ 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:
static VAStatus
intel_encoder_check_jpeg_parameter(VADriverContextP ctx,
- struct encode_state *encode_state,
- struct intel_encoder_context *encoder_context)
+ 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;
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:
static VAStatus
intel_encoder_check_vp8_parameter(VADriverContextP ctx,
- struct encode_state *encode_state,
- struct intel_encoder_context *encoder_context)
+ 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;
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);
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);
encode_state->reference_objects[i++] = obj_surface;
}
- for ( ; i < 16; i++)
+ for (; i < 16; i++)
encode_state->reference_objects[i] = NULL;
encoder_context->is_new_sequence = (is_key_frame && seq_param);
static VAStatus
intel_encoder_check_hevc_parameter(VADriverContextP ctx,
- struct encode_state *encode_state,
- struct intel_encoder_context *encoder_context)
+ 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_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;
- assert(!(pic_param->decoded_curr_pic.flags & VA_PICTURE_HEVC_INVALID));
+ 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)
+ 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);
- assert(obj_surface); /* It is possible the store buffer isn't allocated yet */
-
- if (!obj_surface)
+ 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);
- assert(obj_buffer && obj_buffer->buffer_store && obj_buffer->buffer_store->bo);
+ 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 (!obj_buffer || !obj_buffer->buffer_store || !obj_buffer->buffer_store->bo)
+ 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;
break;
else {
obj_surface = SURFACE(pic_param->reference_frames[i].picture_id);
- assert(obj_surface);
-
- if (!obj_surface)
+ 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;
-
- if (obj_surface->bo)
- encode_state->reference_objects[i] = obj_surface;
- else
- encode_state->reference_objects[i] = NULL; /* FIXME: Warning or Error ??? */
+ }
+ encode_state->reference_objects[i] = obj_surface;
}
}
- for ( ; i < 15; i++)
+ for (; i < 15; i++)
encode_state->reference_objects[i] = NULL;
for (i = 0; i < encode_state->num_slice_params_ext; i++) {
/* 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:
{
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;
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);
encode_state->reference_objects[i++] = NULL;
}
- for ( ; i < 16; i++)
+ 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:
case VAProfileH264High:
case VAProfileH264MultiviewHigh:
case VAProfileH264StereoHigh: {
- vaStatus = intel_encoder_check_avc_parameter(ctx, encode_state, encoder_context);
- if (vaStatus != VA_STATUS_SUCCESS)
+ 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;
- vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context);
- break;
+ }
}
case VAProfileMPEG2Simple:
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)
+ if (vaStatus != VA_STATUS_SUCCESS)
goto out;
vaStatus = intel_encoder_check_yuv_surface(ctx, profile, encode_state, encoder_context);
break;
}
if (vaStatus == VA_STATUS_SUCCESS)
- vaStatus = intel_encoder_check_misc_parameter(ctx, encode_state, encoder_context);
+ vaStatus = intel_encoder_check_misc_parameter(ctx, profile, encode_state, encoder_context);
-out:
+out:
return vaStatus;
}
-
+
static VAStatus
-intel_encoder_end_picture(VADriverContextP ctx,
- VAProfile profile,
+intel_encoder_end_picture(VADriverContextP ctx,
+ VAProfile profile,
union codec_state *codec_state,
struct hw_context *hw_context)
{
encoder_context->mfc_brc_prepare(encode_state, encoder_context);
- if((encoder_context->vme_context && encoder_context->vme_pipeline)) {
+ /* 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;
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);
+ 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);
}
return VA_STATUS_ERROR_UNIMPLEMENTED;
}
-typedef Bool (* hw_init_func)(VADriverContextP, struct intel_encoder_context *);
+typedef Bool(* hw_init_func)(VADriverContextP, struct intel_encoder_context *);
static struct hw_context *
intel_enc_hw_context_init(VADriverContextP ctx,
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;
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;
case VAProfileMPEG2Main:
encoder_context->codec = CODEC_MPEG2;
break;
-
+
case VAProfileH264ConstrainedBaseline:
case VAProfileH264Main:
case VAProfileH264High:
if (obj_config->entrypoint == VAEntrypointEncSliceLP)
encoder_context->quality_range = ENCODER_LP_QUALITY_RANGE;
- else
+ 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:
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) {