return AVERROR(ENOMEM);
if (ctx->input_order == 0 || ctx->force_idr ||
- ctx->gop_counter >= avctx->gop_size) {
+ ctx->gop_counter >= ctx->gop_size) {
pic->type = PICTURE_TYPE_IDR;
ctx->force_idr = 0;
ctx->gop_counter = 1;
// encode-after it, but not exceeding the GOP size.
for (i = 0; i < ctx->b_per_p &&
- ctx->gop_counter < avctx->gop_size; i++) {
+ ctx->gop_counter < ctx->gop_size; i++) {
pic = vaapi_encode_alloc();
if (!pic)
goto fail;
return err;
}
-static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx)
-{
- VAAPIEncodeContext *ctx = avctx->priv_data;
- VAStatus vas;
- int i;
-
- VAConfigAttrib attr[] = {
- { VAConfigAttribEncMaxRefFrames },
- { VAConfigAttribEncPackedHeaders },
- };
-
- vas = vaGetConfigAttributes(ctx->hwctx->display,
- ctx->va_profile, ctx->va_entrypoint,
- attr, FF_ARRAY_ELEMS(attr));
- if (vas != VA_STATUS_SUCCESS) {
- av_log(avctx, AV_LOG_ERROR, "Failed to fetch config "
- "attributes: %d (%s).\n", vas, vaErrorStr(vas));
- return AVERROR(EINVAL);
- }
-
- for (i = 0; i < FF_ARRAY_ELEMS(attr); i++) {
- if (attr[i].value == VA_ATTRIB_NOT_SUPPORTED) {
- // Unfortunately we have to treat this as "don't know" and hope
- // for the best, because the Intel MJPEG encoder returns this
- // for all the interesting attributes.
- av_log(avctx, AV_LOG_DEBUG, "Attribute (%d) is not supported.\n",
- attr[i].type);
- continue;
- }
- switch (attr[i].type) {
- case VAConfigAttribEncMaxRefFrames:
- {
- unsigned int ref_l0 = attr[i].value & 0xffff;
- unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff;
-
- if (avctx->gop_size > 1 && ref_l0 < 1) {
- av_log(avctx, AV_LOG_ERROR, "P frames are not "
- "supported (%#x).\n", attr[i].value);
- return AVERROR(EINVAL);
- }
- if (avctx->max_b_frames > 0 && ref_l1 < 1) {
- av_log(avctx, AV_LOG_WARNING, "B frames are not "
- "supported (%#x) by the underlying driver.\n",
- attr[i].value);
- avctx->max_b_frames = 0;
- }
- }
- break;
- case VAConfigAttribEncPackedHeaders:
- if (ctx->va_packed_headers & ~attr[i].value) {
- // This isn't fatal, but packed headers are always
- // preferable because they are under our control.
- // When absent, the driver is generating them and some
- // features may not work (e.g. VUI or SEI in H.264).
- av_log(avctx, AV_LOG_WARNING, "Warning: some packed "
- "headers are not supported (want %#x, got %#x).\n",
- ctx->va_packed_headers, attr[i].value);
- ctx->va_packed_headers &= attr[i].value;
- }
- ctx->config_attributes[ctx->nb_config_attributes++] =
- (VAConfigAttrib) {
- .type = VAConfigAttribEncPackedHeaders,
- .value = ctx->va_packed_headers,
- };
- break;
- default:
- av_assert0(0 && "Unexpected config attribute.");
- }
- }
-
- return 0;
-}
-
static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
.initial_qp = 0,
.min_qp = (avctx->qmin > 0 ? avctx->qmin : 0),
.basic_unit_size = 0,
+#if VA_CHECK_VERSION(1, 1, 0)
+ .max_qp = (avctx->qmax > 0 ? avctx->qmax : 0),
+#endif
};
vaapi_encode_add_global_param(avctx, &ctx->rc_params.misc,
sizeof(ctx->rc_params));
return 0;
}
+static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx)
+{
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+ VAStatus vas;
+ VAConfigAttrib attr = { VAConfigAttribEncMaxRefFrames };
+ uint32_t ref_l0, ref_l1;
+
+ vas = vaGetConfigAttributes(ctx->hwctx->display,
+ ctx->va_profile,
+ ctx->va_entrypoint,
+ &attr, 1);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to query reference frames "
+ "attribute: %d (%s).\n", vas, vaErrorStr(vas));
+ return AVERROR_EXTERNAL;
+ }
+
+ if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
+ ref_l0 = ref_l1 = 0;
+ } else {
+ ref_l0 = attr.value & 0xffff;
+ ref_l1 = attr.value >> 16 & 0xffff;
+ }
+
+ if (avctx->gop_size <= 1) {
+ av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n");
+ ctx->gop_size = 1;
+ } else if (ref_l0 < 1) {
+ av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
+ "reference frames.\n");
+ return AVERROR(EINVAL);
+ } else if (ref_l1 < 1 || avctx->max_b_frames < 1) {
+ av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames "
+ "(supported references: %d / %d).\n", ref_l0, ref_l1);
+ ctx->gop_size = avctx->gop_size;
+ ctx->p_per_i = INT_MAX;
+ ctx->b_per_p = 0;
+ } else {
+ av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames "
+ "(supported references: %d / %d).\n", ref_l0, ref_l1);
+ ctx->gop_size = avctx->gop_size;
+ ctx->p_per_i = INT_MAX;
+ ctx->b_per_p = avctx->max_b_frames;
+ }
+
+ return 0;
+}
+
+static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx)
+{
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+ VAStatus vas;
+ VAConfigAttrib attr = { VAConfigAttribEncPackedHeaders };
+
+ vas = vaGetConfigAttributes(ctx->hwctx->display,
+ ctx->va_profile,
+ ctx->va_entrypoint,
+ &attr, 1);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to query packed headers "
+ "attribute: %d (%s).\n", vas, vaErrorStr(vas));
+ return AVERROR_EXTERNAL;
+ }
+
+ if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
+ if (ctx->desired_packed_headers) {
+ av_log(avctx, AV_LOG_WARNING, "Driver does not support any "
+ "packed headers (wanted %#x).\n",
+ ctx->desired_packed_headers);
+ } else {
+ av_log(avctx, AV_LOG_VERBOSE, "Driver does not support any "
+ "packed headers (none wanted).\n");
+ }
+ ctx->va_packed_headers = 0;
+ } else {
+ if (ctx->desired_packed_headers & ~attr.value) {
+ av_log(avctx, AV_LOG_WARNING, "Driver does not support some "
+ "wanted packed headers (wanted %#x, found %#x).\n",
+ ctx->desired_packed_headers, attr.value);
+ } else {
+ av_log(avctx, AV_LOG_VERBOSE, "All wanted packed headers "
+ "available (wanted %#x, found %#x).\n",
+ ctx->desired_packed_headers, attr.value);
+ }
+ ctx->va_packed_headers = ctx->desired_packed_headers & attr.value;
+ }
+
+ if (ctx->va_packed_headers) {
+ ctx->config_attributes[ctx->nb_config_attributes++] =
+ (VAConfigAttrib) {
+ .type = VAConfigAttribEncPackedHeaders,
+ .value = ctx->va_packed_headers,
+ };
+ }
+
+ if ( (ctx->desired_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) &&
+ !(ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) &&
+ (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {
+ av_log(avctx, AV_LOG_WARNING, "Driver does not support packed "
+ "sequence headers, but a global header is requested.\n");
+ av_log(avctx, AV_LOG_WARNING, "No global header will be written: "
+ "this may result in a stream which is not usable for some "
+ "purposes (e.g. not muxable to some containers).\n");
+ }
+
+ return 0;
+}
+
static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx)
{
#if VA_CHECK_VERSION(0, 36, 0)
ctx->recon_frames->height = ctx->surface_height;
// At most three IDR/I/P frames and two runs of B frames can be in
// flight at any one time.
- ctx->recon_frames->initial_pool_size = 3 + 2 * avctx->max_b_frames;
+ ctx->recon_frames->initial_pool_size = 3 + 2 * ctx->b_per_p;
err = av_hwframe_ctx_init(ctx->recon_frames_ref);
if (err < 0) {
if (err < 0)
goto fail;
- err = vaapi_encode_config_attributes(avctx);
+ err = vaapi_encode_init_gop_structure(avctx);
+ if (err < 0)
+ goto fail;
+
+ err = vaapi_encode_init_packed_headers(avctx);
if (err < 0)
goto fail;
}
ctx->input_order = 0;
- ctx->output_delay = avctx->max_b_frames;
+ ctx->output_delay = ctx->b_per_p;
ctx->decode_delay = 1;
ctx->output_order = - ctx->output_delay - 1;
- // Currently we never generate I frames, only IDR.
- ctx->p_per_i = INT_MAX;
- ctx->b_per_p = avctx->max_b_frames;
-
if (ctx->codec->sequence_params_size > 0) {
ctx->codec_sequence_params =
av_mallocz(ctx->codec->sequence_params_size);
ctx->issue_mode = ISSUE_MODE_MAXIMISE_THROUGHPUT;
if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE &&
- ctx->codec->write_sequence_header) {
+ ctx->codec->write_sequence_header &&
+ avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
char data[MAX_PARAM_BUFFER_SIZE];
size_t bit_len = 8 * sizeof(data);