/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <inttypes.h>#include <string.h> #include "config.h" #include "libavutil/avassert.h"#include "libavutil/common.h"#include "libavutil/internal.h"#include "libavutil/log.h"#include "libavutil/pixdesc.h" #include "vaapi_encode.h"#include "encode.h"#include "avcodec.h"#include "refstruct.h" const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(VAAPI, VAAPI), NULL,}; static const char * const picture_type_name[] = { "IDR", "I", "P", "B" }; static int vaapi_encode_make_packed_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, char *data, size_t bit_len){ VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; VABufferID param_buffer, data_buffer; VABufferID *tmp; VAEncPackedHeaderParameterBuffer params = { .type = type, .bit_length = bit_len, .has_emulation_bytes = 1, }; tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 2); if (!tmp) return AVERROR(ENOMEM); pic->param_buffers = tmp; vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VAEncPackedHeaderParameterBufferType, sizeof(params), 1, ¶ms, ¶m_buffer); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " "for packed header (type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); return AVERROR(EIO); } pic->param_buffers[pic->nb_param_buffers++] = param_buffer; vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VAEncPackedHeaderDataBufferType, (bit_len + 7) / 8, 1, data, &data_buffer); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create data buffer " "for packed header (type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); return AVERROR(EIO); } pic->param_buffers[pic->nb_param_buffers++] = data_buffer; av_log(avctx, AV_LOG_DEBUG, "Packed header buffer (%d) is %#x/%#x " "(%zu bits).\n", type, param_buffer, data_buffer, bit_len); return 0;} static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, char *data, size_t len){ VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; VABufferID *tmp; VABufferID buffer; tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 1); if (!tmp) return AVERROR(ENOMEM); pic->param_buffers = tmp; vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, type, len, 1, data, &buffer); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " "(type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); return AVERROR(EIO); } pic->param_buffers[pic->nb_param_buffers++] = buffer; av_log(avctx, AV_LOG_DEBUG, "Param buffer (%d) is %#x.\n", type, buffer); return 0;} static int vaapi_encode_make_misc_param_buffer(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, const void *data, size_t len){ // Construct the buffer on the stack - 1KB is much larger than any // current misc parameter buffer type (the largest is EncQuality at // 224 bytes). uint8_t buffer[1024]; VAEncMiscParameterBuffer header = { .type = type, }; size_t buffer_size = sizeof(header) + len; av_assert0(buffer_size <= sizeof(buffer)); memcpy(buffer, &header, sizeof(header)); memcpy(buffer + sizeof(header), data, len); return vaapi_encode_make_param_buffer(avctx, pic, VAEncMiscParameterBufferType, buffer, buffer_size);} static int vaapi_encode_wait(AVCodecContext *avctx, VAAPIEncodePicture *pic){ VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; av_assert0(pic->encode_issued); if (pic->encode_complete) { // Already waited for this picture. return 0; } av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" " "(input surface %#x).\n", pic->display_order, pic->encode_order, pic->input_surface); #if VA_CHECK_VERSION(1, 9, 0) if (ctx->has_sync_buffer_func) { vas = vaSyncBuffer(ctx->hwctx->display, pic->output_buffer, VA_TIMEOUT_INFINITE); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to sync to output buffer completion: " "%d (%s).\n", vas, vaErrorStr(vas)); return AVERROR(EIO); } } else#endif { // If vaSyncBuffer is not implemented, try old version API. vas = vaSyncSurface(ctx->hwctx->display, pic->input_surface); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to sync to picture completion: " "%d (%s).\n", vas, vaErrorStr(vas)); return AVERROR(EIO); } } // Input is definitely finished with now. av_frame_free(&pic->input_image); pic->encode_complete = 1; return 0;} static int vaapi_encode_make_row_slice(AVCodecContext *avctx, VAAPIEncodePicture *pic){ VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeSlice *slice; int i, rounding; for (i = 0; i < pic->nb_slices; i++) pic->slices[i].row_size = ctx->slice_size; rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size; if (rounding > 0) { // Place rounding error at top and bottom of frame. av_assert0(rounding < pic->nb_slices); // Some Intel drivers contain a bug where the encoder will fail // if the last slice is smaller than the one before it. Since // that's straightforward to avoid here, just do so. if (rounding <= 2) { for (i = 0; i < rounding; i++) ++pic->slices[i].row_size; } else { for (i = 0; i < (rounding + 1) / 2; i++) ++pic->slices[pic->nb_slices - i - 1].row_size; for (i = 0; i < rounding / 2; i++) ++pic->slices[i].row_size; } } else if (rounding < 0) { // Remove rounding error from last slice only. av_assert0(rounding < ctx->slice_size); pic->slices[pic->nb_slices - 1].row_size += rounding; } for (i = 0; i < pic->nb_slices; i++) { slice = &pic->slices[i]; slice->index = i; if (i == 0) { slice->row_start = 0; slice->block_start = 0; } else { const VAAPIEncodeSlice *prev = &pic->slices[i - 1]; slice->row_start = prev->row_start + prev->row_size; slice->block_start = prev->block_start + prev->block_size; } slice->block_size = slice->row_size * ctx->slice_block_cols; av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), " "%d-%d (%d blocks).\n", i, slice->row_start, slice->row_start + slice->row_size - 1, slice->row_size, slice->block_start, slice->block_start + slice->block_size - 1, slice->block_size); } return 0;} static int vaapi_encode_make_tile_slice(AVCodecContext *avctx, VAAPIEncodePicture *pic){ VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeSlice *slice; int i, j, index; for (i = 0; i < ctx->tile_cols; i++) { for (j = 0; j < ctx->tile_rows; j++) { index = j * ctx->tile_cols + i; slice = &pic->slices[index]; slice->index = index; pic->slices[index].block_start = ctx->col_bd[i] + ctx->row_bd[j] * ctx->slice_block_cols; pic->slices[index].block_size = ctx->row_height[j] * ctx->col_width[i]; av_log(avctx, AV_LOG_DEBUG, "Slice %2d: (%2d, %2d) start at: %4d " "width:%2d height:%2d (%d blocks).\n", index, ctx->col_bd[i], ctx->row_bd[j], slice->block_start, ctx->col_width[i], ctx->row_height[j], slice->block_size); } } return 0;} static int vaapi_encode_issue(AVCodecContext *avctx, VAAPIEncodePicture *pic){ VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeSlice *slice; VAStatus vas; int err, i; char data[MAX_PARAM_BUFFER_SIZE]; size_t bit_len; av_unused AVFrameSideData *sd; av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " "as type %s.\n", pic->display_order, pic->encode_order, picture_type_name[pic->type]); if (pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0) { av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n"); } else { av_log(avctx, AV_LOG_DEBUG, "L0 refers to"); for (i = 0; i < pic->nb_refs[0]; i++) { av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, pic->refs[0][i]->display_order, pic->refs[0][i]->encode_order); } av_log(avctx, AV_LOG_DEBUG, ".\n"); if (pic->nb_refs[1]) { av_log(avctx, AV_LOG_DEBUG, "L1 refers to"); for (i = 0; i < pic->nb_refs[1]; i++) { av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, pic->refs[1][i]->display_order, pic->refs[1][i]->encode_order); } av_log(avctx, AV_LOG_DEBUG, ".\n"); } } av_assert0(!pic->encode_issued); for (i = 0; i < pic->nb_refs[0]; i++) { av_assert0(pic->refs[0][i]); av_assert0(pic->refs[0][i]->encode_issued); } for (i = 0; i < pic->nb_refs[1]; i++) { av_assert0(pic->refs[1][i]); av_assert0(pic->refs[1][i]->encode_issued); } av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface); pic->recon_image = av_frame_alloc(); if (!pic->recon_image) { err = AVERROR(ENOMEM); goto fail; } err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0); if (err < 0) { err = AVERROR(ENOMEM); goto fail; } pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3]; av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface); pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool); if (!pic->output_buffer_ref) { err = AVERROR(ENOMEM); goto fail; } pic->output_buffer = *pic->output_buffer_ref; av_log(avctx, AV_LOG_DEBUG, "Output buffer is %#x.\n", pic->output_buffer); if (ctx->codec->picture_params_size > 0) { pic->codec_picture_params = av_malloc(ctx->codec->picture_params_size); if (!pic->codec_picture_params) goto fail; memcpy(pic->codec_picture_params, ctx->codec_picture_params, ctx->codec->picture_params_size); } else { av_assert0(!ctx->codec_picture_params); } pic->nb_param_buffers = 0; if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { err = vaapi_encode_make_param_buffer(avctx, pic, VAEncSequenceParameterBufferType, ctx->codec_sequence_params, ctx->codec->sequence_params_size); if (err < 0) goto fail; } if (pic->type == PICTURE_TYPE_IDR) { for (i = 0; i < ctx->nb_global_params; i++) { err = vaapi_encode_make_misc_param_buffer(avctx, pic, ctx->global_params_type[i], ctx->global_params[i], ctx->global_params_size[i]); if (err < 0) goto fail; } } if (ctx->codec->init_picture_params) { err = ctx->codec->init_picture_params(avctx, pic); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture " "parameters: %d.\n", err); goto fail; } err = vaapi_encode_make_param_buffer(avctx, pic, VAEncPictureParameterBufferType, pic->codec_picture_params, ctx->codec->picture_params_size); if (err < 0) goto fail; } #if VA_CHECK_VERSION(1, 5, 0) if (ctx->max_frame_size) { err = vaapi_encode_make_misc_param_buffer(avctx, pic, VAEncMiscParameterTypeMaxFrameSize, &ctx->mfs_params, sizeof(ctx->mfs_params)); if (err < 0) goto fail; }#endif if (pic->type == PICTURE_TYPE_IDR) { if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE && ctx->codec->write_sequence_header) { bit_len = 8 * sizeof(data); err = ctx->codec->write_sequence_header(avctx, data, &bit_len); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence " "header: %d.\n", err); goto fail; } err = vaapi_encode_make_packed_header(avctx, pic, ctx->codec->sequence_header_type, data, bit_len); if (err < 0) goto fail; } } if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_PICTURE && ctx->codec->write_picture_header) { bit_len = 8 * sizeof(data); err = ctx->codec->write_picture_header(avctx, pic, data, &bit_len); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write per-picture " "header: %d.\n", err); goto fail; } err = vaapi_encode_make_packed_header(avctx, pic, ctx->codec->picture_header_type, data, bit_len); if (err < 0) goto fail; } if (ctx->codec->write_extra_buffer) { for (i = 0;; i++) { size_t len = sizeof(data); int type; err = ctx->codec->write_extra_buffer(avctx, pic, i, &type, data, &len); if (err == AVERROR_EOF) break; if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write extra " "buffer %d: %d.\n", i, err); goto fail; } err = vaapi_encode_make_param_buffer(avctx, pic, type, data, len); if (err < 0) goto fail; } } if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_MISC && ctx->codec->write_extra_header) { for (i = 0;; i++) { int type; bit_len = 8 * sizeof(data); err = ctx->codec->write_extra_header(avctx, pic, i, &type, data, &bit_len); if (err == AVERROR_EOF) break; if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write extra " "header %d: %d.\n", i, err); goto fail; } err = vaapi_encode_make_packed_header(avctx, pic, type, data, bit_len); if (err < 0) goto fail; } } if (pic->nb_slices == 0) pic->nb_slices = ctx->nb_slices; if (pic->nb_slices > 0) { pic->slices = av_calloc(pic->nb_slices, sizeof(*pic->slices)); if (!pic->slices) { err = AVERROR(ENOMEM); goto fail; } if (ctx->tile_rows && ctx->tile_cols) vaapi_encode_make_tile_slice(avctx, pic); else vaapi_encode_make_row_slice(avctx, pic); } for (i = 0; i < pic->nb_slices; i++) { slice = &pic->slices[i]; if (ctx->codec->slice_params_size > 0) { slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); if (!slice->codec_slice_params) { err = AVERROR(ENOMEM); goto fail; } } if (ctx->codec->init_slice_params) { err = ctx->codec->init_slice_params(avctx, pic, slice); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise slice " "parameters: %d.\n", err);Lines 1–500 of 2994. Load more
/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <inttypes.h> #include <string.h> #include "config.h" #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/pixdesc.h" #include "vaapi_encode.h" #include "encode.h" #include "avcodec.h" #include "refstruct.h" const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = { HW_CONFIG_ENCODER_FRAMES(VAAPI, VAAPI), NULL, }; static const char * const picture_type_name[] = { "IDR", "I", "P", "B" }; static int vaapi_encode_make_packed_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, char *data, size_t bit_len) { VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; VABufferID param_buffer, data_buffer; VABufferID *tmp; VAEncPackedHeaderParameterBuffer params = { .type = type, .bit_length = bit_len, .has_emulation_bytes = 1, }; tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 2); if (!tmp) return AVERROR(ENOMEM); pic->param_buffers = tmp; vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VAEncPackedHeaderParameterBufferType, sizeof(params), 1, ¶ms, ¶m_buffer); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " "for packed header (type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); return AVERROR(EIO); } pic->param_buffers[pic->nb_param_buffers++] = param_buffer; vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VAEncPackedHeaderDataBufferType, (bit_len + 7) / 8, 1, data, &data_buffer); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create data buffer " "for packed header (type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); return AVERROR(EIO); } pic->param_buffers[pic->nb_param_buffers++] = data_buffer; av_log(avctx, AV_LOG_DEBUG, "Packed header buffer (%d) is %#x/%#x " "(%zu bits).\n", type, param_buffer, data_buffer, bit_len); return 0; } static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, char *data, size_t len) { VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; VABufferID *tmp; VABufferID buffer; tmp = av_realloc_array(pic->param_buffers, sizeof(*tmp), pic->nb_param_buffers + 1); if (!tmp) return AVERROR(ENOMEM); pic->param_buffers = tmp; vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, type, len, 1, data, &buffer); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " "(type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); return AVERROR(EIO); } pic->param_buffers[pic->nb_param_buffers++] = buffer; av_log(avctx, AV_LOG_DEBUG, "Param buffer (%d) is %#x.\n", type, buffer); return 0; } static int vaapi_encode_make_misc_param_buffer(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, const void *data, size_t len) { // Construct the buffer on the stack - 1KB is much larger than any // current misc parameter buffer type (the largest is EncQuality at // 224 bytes). uint8_t buffer[1024]; VAEncMiscParameterBuffer header = { .type = type, }; size_t buffer_size = sizeof(header) + len; av_assert0(buffer_size <= sizeof(buffer)); memcpy(buffer, &header, sizeof(header)); memcpy(buffer + sizeof(header), data, len); return vaapi_encode_make_param_buffer(avctx, pic, VAEncMiscParameterBufferType, buffer, buffer_size); } static int vaapi_encode_wait(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; av_assert0(pic->encode_issued); if (pic->encode_complete) { // Already waited for this picture. return 0; } av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" " "(input surface %#x).\n", pic->display_order, pic->encode_order, pic->input_surface); #if VA_CHECK_VERSION(1, 9, 0) if (ctx->has_sync_buffer_func) { vas = vaSyncBuffer(ctx->hwctx->display, pic->output_buffer, VA_TIMEOUT_INFINITE); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to sync to output buffer completion: " "%d (%s).\n", vas, vaErrorStr(vas)); return AVERROR(EIO); } } else #endif { // If vaSyncBuffer is not implemented, try old version API. vas = vaSyncSurface(ctx->hwctx->display, pic->input_surface); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to sync to picture completion: " "%d (%s).\n", vas, vaErrorStr(vas)); return AVERROR(EIO); } } // Input is definitely finished with now. av_frame_free(&pic->input_image); pic->encode_complete = 1; return 0; } static int vaapi_encode_make_row_slice(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeSlice *slice; int i, rounding; for (i = 0; i < pic->nb_slices; i++) pic->slices[i].row_size = ctx->slice_size; rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size; if (rounding > 0) { // Place rounding error at top and bottom of frame. av_assert0(rounding < pic->nb_slices); // Some Intel drivers contain a bug where the encoder will fail // if the last slice is smaller than the one before it. Since // that's straightforward to avoid here, just do so. if (rounding <= 2) { for (i = 0; i < rounding; i++) ++pic->slices[i].row_size; } else { for (i = 0; i < (rounding + 1) / 2; i++) ++pic->slices[pic->nb_slices - i - 1].row_size; for (i = 0; i < rounding / 2; i++) ++pic->slices[i].row_size; } } else if (rounding < 0) { // Remove rounding error from last slice only. av_assert0(rounding < ctx->slice_size); pic->slices[pic->nb_slices - 1].row_size += rounding; } for (i = 0; i < pic->nb_slices; i++) { slice = &pic->slices[i]; slice->index = i; if (i == 0) { slice->row_start = 0; slice->block_start = 0; } else { const VAAPIEncodeSlice *prev = &pic->slices[i - 1]; slice->row_start = prev->row_start + prev->row_size; slice->block_start = prev->block_start + prev->block_size; } slice->block_size = slice->row_size * ctx->slice_block_cols; av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), " "%d-%d (%d blocks).\n", i, slice->row_start, slice->row_start + slice->row_size - 1, slice->row_size, slice->block_start, slice->block_start + slice->block_size - 1, slice->block_size); } return 0; } static int vaapi_encode_make_tile_slice(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeSlice *slice; int i, j, index; for (i = 0; i < ctx->tile_cols; i++) { for (j = 0; j < ctx->tile_rows; j++) { index = j * ctx->tile_cols + i; slice = &pic->slices[index]; slice->index = index; pic->slices[index].block_start = ctx->col_bd[i] + ctx->row_bd[j] * ctx->slice_block_cols; pic->slices[index].block_size = ctx->row_height[j] * ctx->col_width[i]; av_log(avctx, AV_LOG_DEBUG, "Slice %2d: (%2d, %2d) start at: %4d " "width:%2d height:%2d (%d blocks).\n", index, ctx->col_bd[i], ctx->row_bd[j], slice->block_start, ctx->col_width[i], ctx->row_height[j], slice->block_size); } } return 0; } static int vaapi_encode_issue(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeSlice *slice; VAStatus vas; int err, i; char data[MAX_PARAM_BUFFER_SIZE]; size_t bit_len; av_unused AVFrameSideData *sd; av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " "as type %s.\n", pic->display_order, pic->encode_order, picture_type_name[pic->type]); if (pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0) { av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n"); } else { av_log(avctx, AV_LOG_DEBUG, "L0 refers to"); for (i = 0; i < pic->nb_refs[0]; i++) { av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, pic->refs[0][i]->display_order, pic->refs[0][i]->encode_order); } av_log(avctx, AV_LOG_DEBUG, ".\n"); if (pic->nb_refs[1]) { av_log(avctx, AV_LOG_DEBUG, "L1 refers to"); for (i = 0; i < pic->nb_refs[1]; i++) { av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, pic->refs[1][i]->display_order, pic->refs[1][i]->encode_order); } av_log(avctx, AV_LOG_DEBUG, ".\n"); } } av_assert0(!pic->encode_issued); for (i = 0; i < pic->nb_refs[0]; i++) { av_assert0(pic->refs[0][i]); av_assert0(pic->refs[0][i]->encode_issued); } for (i = 0; i < pic->nb_refs[1]; i++) { av_assert0(pic->refs[1][i]); av_assert0(pic->refs[1][i]->encode_issued); } av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface); pic->recon_image = av_frame_alloc(); if (!pic->recon_image) { err = AVERROR(ENOMEM); goto fail; } err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0); if (err < 0) { err = AVERROR(ENOMEM); goto fail; } pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3]; av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface); pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool); if (!pic->output_buffer_ref) { err = AVERROR(ENOMEM); goto fail; } pic->output_buffer = *pic->output_buffer_ref; av_log(avctx, AV_LOG_DEBUG, "Output buffer is %#x.\n", pic->output_buffer); if (ctx->codec->picture_params_size > 0) { pic->codec_picture_params = av_malloc(ctx->codec->picture_params_size); if (!pic->codec_picture_params) goto fail; memcpy(pic->codec_picture_params, ctx->codec_picture_params, ctx->codec->picture_params_size); } else { av_assert0(!ctx->codec_picture_params); } pic->nb_param_buffers = 0; if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { err = vaapi_encode_make_param_buffer(avctx, pic, VAEncSequenceParameterBufferType, ctx->codec_sequence_params, ctx->codec->sequence_params_size); if (err < 0) goto fail; } if (pic->type == PICTURE_TYPE_IDR) { for (i = 0; i < ctx->nb_global_params; i++) { err = vaapi_encode_make_misc_param_buffer(avctx, pic, ctx->global_params_type[i], ctx->global_params[i], ctx->global_params_size[i]); if (err < 0) goto fail; } } if (ctx->codec->init_picture_params) { err = ctx->codec->init_picture_params(avctx, pic); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture " "parameters: %d.\n", err); goto fail; } err = vaapi_encode_make_param_buffer(avctx, pic, VAEncPictureParameterBufferType, pic->codec_picture_params, ctx->codec->picture_params_size); if (err < 0) goto fail; } #if VA_CHECK_VERSION(1, 5, 0) if (ctx->max_frame_size) { err = vaapi_encode_make_misc_param_buffer(avctx, pic, VAEncMiscParameterTypeMaxFrameSize, &ctx->mfs_params, sizeof(ctx->mfs_params)); if (err < 0) goto fail; } #endif if (pic->type == PICTURE_TYPE_IDR) { if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE && ctx->codec->write_sequence_header) { bit_len = 8 * sizeof(data); err = ctx->codec->write_sequence_header(avctx, data, &bit_len); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence " "header: %d.\n", err); goto fail; } err = vaapi_encode_make_packed_header(avctx, pic, ctx->codec->sequence_header_type, data, bit_len); if (err < 0) goto fail; } } if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_PICTURE && ctx->codec->write_picture_header) { bit_len = 8 * sizeof(data); err = ctx->codec->write_picture_header(avctx, pic, data, &bit_len); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write per-picture " "header: %d.\n", err); goto fail; } err = vaapi_encode_make_packed_header(avctx, pic, ctx->codec->picture_header_type, data, bit_len); if (err < 0) goto fail; } if (ctx->codec->write_extra_buffer) { for (i = 0;; i++) { size_t len = sizeof(data); int type; err = ctx->codec->write_extra_buffer(avctx, pic, i, &type, data, &len); if (err == AVERROR_EOF) break; if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write extra " "buffer %d: %d.\n", i, err); goto fail; } err = vaapi_encode_make_param_buffer(avctx, pic, type, data, len); if (err < 0) goto fail; } } if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_MISC && ctx->codec->write_extra_header) { for (i = 0;; i++) { int type; bit_len = 8 * sizeof(data); err = ctx->codec->write_extra_header(avctx, pic, i, &type, data, &bit_len); if (err == AVERROR_EOF) break; if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write extra " "header %d: %d.\n", i, err); goto fail; } err = vaapi_encode_make_packed_header(avctx, pic, type, data, bit_len); if (err < 0) goto fail; } } if (pic->nb_slices == 0) pic->nb_slices = ctx->nb_slices; if (pic->nb_slices > 0) { pic->slices = av_calloc(pic->nb_slices, sizeof(*pic->slices)); if (!pic->slices) { err = AVERROR(ENOMEM); goto fail; } if (ctx->tile_rows && ctx->tile_cols) vaapi_encode_make_tile_slice(avctx, pic); else vaapi_encode_make_row_slice(avctx, pic); } for (i = 0; i < pic->nb_slices; i++) { slice = &pic->slices[i]; if (ctx->codec->slice_params_size > 0) { slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); if (!slice->codec_slice_params) { err = AVERROR(ENOMEM); goto fail; } } if (ctx->codec->init_slice_params) { err = ctx->codec->init_slice_params(avctx, pic, slice); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise slice " "parameters: %d.\n", err);