| @@ -0,0 +1,1096 @@ |
| | 1 | /* |
| | 2 | * This file is part of Libav. |
| | 3 | * |
| | 4 | * Libav is free software; you can redistribute it and/or |
| | 5 | * modify it under the terms of the GNU Lesser General Public |
| | 6 | * License as published by the Free Software Foundation; either |
| | 7 | * version 2.1 of the License, or (at your option) any later version. |
| | 8 | * |
| | 9 | * Libav is distributed in the hope that it will be useful, |
| | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 12 | * Lesser General Public License for more details. |
| | 13 | * |
| | 14 | * You should have received a copy of the GNU Lesser General Public |
| | 15 | * License along with Libav; if not, write to the Free Software |
| | 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | 17 | */ |
| | 18 | |
| | 19 | #include <inttypes.h> |
| | 20 | #include <string.h> |
| | 21 | |
| | 22 | #include "libavutil/avassert.h" |
| | 23 | #include "libavutil/log.h" |
| | 24 | #include "libavutil/pixdesc.h" |
| | 25 | |
| | 26 | #include "vaapi_encode.h" |
| | 27 | #include "avcodec.h" |
| | 28 | |
| | 29 | static const char *picture_type_name[] = { "IDR", "I", "P", "B" }; |
| | 30 | |
| | 31 | static int vaapi_encode_make_packed_header(AVCodecContext *avctx, |
| | 32 | VAAPIEncodePicture *pic, |
| | 33 | int type, char *data, size_t bit_len) |
| | 34 | { |
| | 35 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 36 | VAStatus vas; |
| | 37 | VABufferID param_buffer, data_buffer; |
| | 38 | VAEncPackedHeaderParameterBuffer params = { |
| | 39 | .type = type, |
| | 40 | .bit_length = bit_len, |
| | 41 | .has_emulation_bytes = 1, |
| | 42 | }; |
| | 43 | |
| | 44 | av_assert0(pic->nb_param_buffers + 2 <= MAX_PARAM_BUFFERS); |
| | 45 | |
| | 46 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, |
| | 47 | VAEncPackedHeaderParameterBufferType, |
| | 48 | sizeof(params), 1, ¶ms, ¶m_buffer); |
| | 49 | if (vas != VA_STATUS_SUCCESS) { |
| | 50 | av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " |
| | 51 | "for packed header (type %d): %d (%s).\n", |
| | 52 | type, vas, vaErrorStr(vas)); |
| | 53 | return AVERROR(EIO); |
| | 54 | } |
| | 55 | pic->param_buffers[pic->nb_param_buffers++] = param_buffer; |
| | 56 | |
| | 57 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, |
| | 58 | VAEncPackedHeaderDataBufferType, |
| | 59 | (bit_len + 7) / 8, 1, data, &data_buffer); |
| | 60 | if (vas != VA_STATUS_SUCCESS) { |
| | 61 | av_log(avctx, AV_LOG_ERROR, "Failed to create data buffer " |
| | 62 | "for packed header (type %d): %d (%s).\n", |
| | 63 | type, vas, vaErrorStr(vas)); |
| | 64 | return AVERROR(EIO); |
| | 65 | } |
| | 66 | pic->param_buffers[pic->nb_param_buffers++] = data_buffer; |
| | 67 | |
| | 68 | av_log(avctx, AV_LOG_DEBUG, "Packed header buffer (%d) is %#x/%#x " |
| | 69 | "(%zu bits).\n", type, param_buffer, data_buffer, bit_len); |
| | 70 | return 0; |
| | 71 | } |
| | 72 | |
| | 73 | static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, |
| | 74 | VAAPIEncodePicture *pic, |
| | 75 | int type, char *data, size_t len) |
| | 76 | { |
| | 77 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 78 | VAStatus vas; |
| | 79 | VABufferID buffer; |
| | 80 | |
| | 81 | av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS); |
| | 82 | |
| | 83 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, |
| | 84 | type, len, 1, data, &buffer); |
| | 85 | if (vas != VA_STATUS_SUCCESS) { |
| | 86 | av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " |
| | 87 | "(type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); |
| | 88 | return AVERROR(EIO); |
| | 89 | } |
| | 90 | pic->param_buffers[pic->nb_param_buffers++] = buffer; |
| | 91 | |
| | 92 | av_log(avctx, AV_LOG_DEBUG, "Param buffer (%d) is %#x.\n", |
| | 93 | type, buffer); |
| | 94 | return 0; |
| | 95 | } |
| | 96 | |
| | 97 | static int vaapi_encode_wait(AVCodecContext *avctx, |
| | 98 | VAAPIEncodePicture *pic) |
| | 99 | { |
| | 100 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 101 | VAStatus vas; |
| | 102 | |
| | 103 | av_assert0(pic->encode_issued); |
| | 104 | |
| | 105 | if (pic->encode_complete) { |
| | 106 | // Already waited for this picture. |
| | 107 | return 0; |
| | 108 | } |
| | 109 | |
| | 110 | av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" " |
| | 111 | "(recon surface %#x).\n", pic->display_order, |
| | 112 | pic->encode_order, pic->recon_surface); |
| | 113 | |
| | 114 | vas = vaSyncSurface(ctx->hwctx->display, pic->recon_surface); |
| | 115 | if (vas != VA_STATUS_SUCCESS) { |
| | 116 | av_log(avctx, AV_LOG_ERROR, "Failed to sync to picture completion: " |
| | 117 | "%d (%s).\n", vas, vaErrorStr(vas)); |
| | 118 | return AVERROR(EIO); |
| | 119 | } |
| | 120 | |
| | 121 | // Input is definitely finished with now. |
| | 122 | av_frame_free(&pic->input_image); |
| | 123 | |
| | 124 | pic->encode_complete = 1; |
| | 125 | return 0; |
| | 126 | } |
| | 127 | |
| | 128 | static int vaapi_encode_issue(AVCodecContext *avctx, |
| | 129 | VAAPIEncodePicture *pic) |
| | 130 | { |
| | 131 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 132 | VAAPIEncodeSlice *slice; |
| | 133 | VAStatus vas; |
| | 134 | int err, i; |
| | 135 | char data[MAX_PARAM_BUFFER_SIZE]; |
| | 136 | size_t bit_len; |
| | 137 | |
| | 138 | av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " |
| | 139 | "as type %s.\n", pic->display_order, pic->encode_order, |
| | 140 | picture_type_name[pic->type]); |
| | 141 | if (pic->nb_refs == 0) { |
| | 142 | av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n"); |
| | 143 | } else { |
| | 144 | av_log(avctx, AV_LOG_DEBUG, "Refers to:"); |
| | 145 | for (i = 0; i < pic->nb_refs; i++) { |
| | 146 | av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, |
| | 147 | pic->refs[i]->display_order, pic->refs[i]->encode_order); |
| | 148 | } |
| | 149 | av_log(avctx, AV_LOG_DEBUG, ".\n"); |
| | 150 | } |
| | 151 | |
| | 152 | av_assert0(pic->input_available && !pic->encode_issued); |
| | 153 | for (i = 0; i < pic->nb_refs; i++) { |
| | 154 | av_assert0(pic->refs[i]); |
| | 155 | // If we are serialised then the references must have already |
| | 156 | // completed. If not, they must have been issued but need not |
| | 157 | // have completed yet. |
| | 158 | if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING) |
| | 159 | av_assert0(pic->refs[i]->encode_complete); |
| | 160 | else |
| | 161 | av_assert0(pic->refs[i]->encode_issued); |
| | 162 | } |
| | 163 | |
| | 164 | av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface); |
| | 165 | |
| | 166 | pic->recon_image = av_frame_alloc(); |
| | 167 | if (!pic->recon_image) { |
| | 168 | err = AVERROR(ENOMEM); |
| | 169 | goto fail; |
| | 170 | } |
| | 171 | |
| | 172 | err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0); |
| | 173 | if (err < 0) { |
| | 174 | err = AVERROR(ENOMEM); |
| | 175 | goto fail; |
| | 176 | } |
| | 177 | pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3]; |
| | 178 | av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface); |
| | 179 | |
| | 180 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, |
| | 181 | VAEncCodedBufferType, |
| | 182 | MAX_OUTPUT_BUFFER_SIZE, 1, 0, |
| | 183 | &pic->output_buffer); |
| | 184 | if (vas != VA_STATUS_SUCCESS) { |
| | 185 | av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream " |
| | 186 | "output buffer: %d (%s).\n", vas, vaErrorStr(vas)); |
| | 187 | err = AVERROR(ENOMEM); |
| | 188 | goto fail; |
| | 189 | } |
| | 190 | av_log(avctx, AV_LOG_DEBUG, "Output buffer is %#x.\n", |
| | 191 | pic->output_buffer); |
| | 192 | |
| | 193 | if (ctx->codec->picture_params_size > 0) { |
| | 194 | pic->codec_picture_params = av_malloc(ctx->codec->picture_params_size); |
| | 195 | if (!pic->codec_picture_params) |
| | 196 | goto fail; |
| | 197 | memcpy(pic->codec_picture_params, ctx->codec_picture_params, |
| | 198 | ctx->codec->picture_params_size); |
| | 199 | } else { |
| | 200 | av_assert0(!ctx->codec_picture_params); |
| | 201 | } |
| | 202 | |
| | 203 | pic->nb_param_buffers = 0; |
| | 204 | |
| | 205 | if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { |
| | 206 | err = vaapi_encode_make_param_buffer(avctx, pic, |
| | 207 | VAEncSequenceParameterBufferType, |
| | 208 | ctx->codec_sequence_params, |
| | 209 | ctx->codec->sequence_params_size); |
| | 210 | if (err < 0) |
| | 211 | goto fail; |
| | 212 | } |
| | 213 | |
| | 214 | if (ctx->codec->init_picture_params) { |
| | 215 | err = ctx->codec->init_picture_params(avctx, pic); |
| | 216 | if (err < 0) { |
| | 217 | av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture " |
| | 218 | "parameters: %d.\n", err); |
| | 219 | goto fail; |
| | 220 | } |
| | 221 | err = vaapi_encode_make_param_buffer(avctx, pic, |
| | 222 | VAEncPictureParameterBufferType, |
| | 223 | pic->codec_picture_params, |
| | 224 | ctx->codec->picture_params_size); |
| | 225 | if (err < 0) |
| | 226 | goto fail; |
| | 227 | } |
| | 228 | |
| | 229 | if (pic->type == PICTURE_TYPE_IDR) { |
| | 230 | if (ctx->codec->write_sequence_header) { |
| | 231 | bit_len = 8 * sizeof(data); |
| | 232 | err = ctx->codec->write_sequence_header(avctx, data, &bit_len); |
| | 233 | if (err < 0) { |
| | 234 | av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence " |
| | 235 | "header: %d.\n", err); |
| | 236 | goto fail; |
| | 237 | } |
| | 238 | err = vaapi_encode_make_packed_header(avctx, pic, |
| | 239 | ctx->codec->sequence_header_type, |
| | 240 | data, bit_len); |
| | 241 | if (err < 0) |
| | 242 | goto fail; |
| | 243 | } |
| | 244 | } |
| | 245 | |
| | 246 | if (ctx->codec->write_picture_header) { |
| | 247 | bit_len = 8 * sizeof(data); |
| | 248 | err = ctx->codec->write_picture_header(avctx, pic, data, &bit_len); |
| | 249 | if (err < 0) { |
| | 250 | av_log(avctx, AV_LOG_ERROR, "Failed to write per-picture " |
| | 251 | "header: %d.\n", err); |
| | 252 | goto fail; |
| | 253 | } |
| | 254 | err = vaapi_encode_make_packed_header(avctx, pic, |
| | 255 | ctx->codec->picture_header_type, |
| | 256 | data, bit_len); |
| | 257 | if (err < 0) |
| | 258 | goto fail; |
| | 259 | } |
| | 260 | |
| | 261 | if (ctx->codec->write_extra_buffer) { |
| | 262 | for (i = 0;; i++) { |
| | 263 | size_t len = sizeof(data); |
| | 264 | int type; |
| | 265 | err = ctx->codec->write_extra_buffer(avctx, pic, i, &type, |
| | 266 | data, &len); |
| | 267 | if (err == AVERROR_EOF) |
| | 268 | break; |
| | 269 | if (err < 0) { |
| | 270 | av_log(avctx, AV_LOG_ERROR, "Failed to write extra " |
| | 271 | "buffer %d: %d.\n", i, err); |
| | 272 | goto fail; |
| | 273 | } |
| | 274 | |
| | 275 | err = vaapi_encode_make_param_buffer(avctx, pic, type, |
| | 276 | data, len); |
| | 277 | if (err < 0) |
| | 278 | goto fail; |
| | 279 | } |
| | 280 | } |
| | 281 | |
| | 282 | av_assert0(pic->nb_slices <= MAX_PICTURE_SLICES); |
| | 283 | for (i = 0; i < pic->nb_slices; i++) { |
| | 284 | slice = av_mallocz(sizeof(*slice)); |
| | 285 | if (!slice) { |
| | 286 | err = AVERROR(ENOMEM); |
| | 287 | goto fail; |
| | 288 | } |
| | 289 | pic->slices[i] = slice; |
| | 290 | |
| | 291 | if (ctx->codec->slice_params_size > 0) { |
| | 292 | slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); |
| | 293 | if (!slice->codec_slice_params) { |
| | 294 | err = AVERROR(ENOMEM); |
| | 295 | goto fail; |
| | 296 | } |
| | 297 | } |
| | 298 | |
| | 299 | if (ctx->codec->init_slice_params) { |
| | 300 | err = ctx->codec->init_slice_params(avctx, pic, slice); |
| | 301 | if (err < 0) { |
| | 302 | av_log(avctx, AV_LOG_ERROR, "Failed to initalise slice " |
| | 303 | "parameters: %d.\n", err); |
| | 304 | goto fail; |
| | 305 | } |
| | 306 | } |
| | 307 | |
| | 308 | if (ctx->codec->write_slice_header) { |
| | 309 | bit_len = 8 * sizeof(data); |
| | 310 | err = ctx->codec->write_slice_header(avctx, pic, slice, |
| | 311 | data, &bit_len); |
| | 312 | if (err < 0) { |
| | 313 | av_log(avctx, AV_LOG_ERROR, "Failed to write per-slice " |
| | 314 | "header: %d.\n", err); |
| | 315 | goto fail; |
| | 316 | } |
| | 317 | err = vaapi_encode_make_packed_header(avctx, pic, |
| | 318 | ctx->codec->slice_header_type, |
| | 319 | data, bit_len); |
| | 320 | if (err < 0) |
| | 321 | goto fail; |
| | 322 | } |
| | 323 | |
| | 324 | if (ctx->codec->init_slice_params) { |
| | 325 | err = vaapi_encode_make_param_buffer(avctx, pic, |
| | 326 | VAEncSliceParameterBufferType, |
| | 327 | slice->codec_slice_params, |
| | 328 | ctx->codec->slice_params_size); |
| | 329 | if (err < 0) |
| | 330 | goto fail; |
| | 331 | } |
| | 332 | } |
| | 333 | |
| | 334 | vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, |
| | 335 | pic->input_surface); |
| | 336 | if (vas != VA_STATUS_SUCCESS) { |
| | 337 | av_log(avctx, AV_LOG_ERROR, "Failed to begin picture encode issue: " |
| | 338 | "%d (%s).\n", vas, vaErrorStr(vas)); |
| | 339 | err = AVERROR(EIO); |
| | 340 | goto fail_with_picture; |
| | 341 | } |
| | 342 | |
| | 343 | vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, |
| | 344 | pic->param_buffers, pic->nb_param_buffers); |
| | 345 | if (vas != VA_STATUS_SUCCESS) { |
| | 346 | av_log(avctx, AV_LOG_ERROR, "Failed to upload encode parameters: " |
| | 347 | "%d (%s).\n", vas, vaErrorStr(vas)); |
| | 348 | err = AVERROR(EIO); |
| | 349 | goto fail_with_picture; |
| | 350 | } |
| | 351 | |
| | 352 | vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); |
| | 353 | if (vas != VA_STATUS_SUCCESS) { |
| | 354 | av_log(avctx, AV_LOG_ERROR, "Failed to end picture encode issue: " |
| | 355 | "%d (%s).\n", vas, vaErrorStr(vas)); |
| | 356 | err = AVERROR(EIO); |
| | 357 | goto fail_at_end; |
| | 358 | } |
| | 359 | |
| | 360 | pic->encode_issued = 1; |
| | 361 | |
| | 362 | if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING) |
| | 363 | return vaapi_encode_wait(avctx, pic); |
| | 364 | else |
| | 365 | return 0; |
| | 366 | |
| | 367 | fail_with_picture: |
| | 368 | vaEndPicture(ctx->hwctx->display, ctx->va_context); |
| | 369 | fail: |
| | 370 | for(i = 0; i < pic->nb_param_buffers; i++) |
| | 371 | vaDestroyBuffer(ctx->hwctx->display, pic->param_buffers[i]); |
| | 372 | fail_at_end: |
| | 373 | av_freep(&pic->codec_picture_params); |
| | 374 | av_frame_free(&pic->recon_image); |
| | 375 | return err; |
| | 376 | } |
| | 377 | |
| | 378 | static int vaapi_encode_output(AVCodecContext *avctx, |
| | 379 | VAAPIEncodePicture *pic, AVPacket *pkt) |
| | 380 | { |
| | 381 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 382 | VACodedBufferSegment *buf_list, *buf; |
| | 383 | VAStatus vas; |
| | 384 | int err; |
| | 385 | |
| | 386 | err = vaapi_encode_wait(avctx, pic); |
| | 387 | if (err < 0) |
| | 388 | return err; |
| | 389 | |
| | 390 | buf_list = NULL; |
| | 391 | vas = vaMapBuffer(ctx->hwctx->display, pic->output_buffer, |
| | 392 | (void**)&buf_list); |
| | 393 | if (vas != VA_STATUS_SUCCESS) { |
| | 394 | av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: " |
| | 395 | "%d (%s).\n", vas, vaErrorStr(vas)); |
| | 396 | err = AVERROR(EIO); |
| | 397 | goto fail; |
| | 398 | } |
| | 399 | |
| | 400 | for (buf = buf_list; buf; buf = buf->next) { |
| | 401 | av_log(avctx, AV_LOG_DEBUG, "Output buffer: %u bytes " |
| | 402 | "(status %08x).\n", buf->size, buf->status); |
| | 403 | |
| | 404 | err = av_new_packet(pkt, buf->size); |
| | 405 | if (err < 0) |
| | 406 | goto fail; |
| | 407 | |
| | 408 | memcpy(pkt->data, buf->buf, buf->size); |
| | 409 | } |
| | 410 | |
| | 411 | if (pic->type == PICTURE_TYPE_IDR) |
| | 412 | pkt->flags |= AV_PKT_FLAG_KEY; |
| | 413 | |
| | 414 | pkt->pts = pic->pts; |
| | 415 | |
| | 416 | vas = vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer); |
| | 417 | if (vas != VA_STATUS_SUCCESS) { |
| | 418 | av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: " |
| | 419 | "%d (%s).\n", vas, vaErrorStr(vas)); |
| | 420 | err = AVERROR(EIO); |
| | 421 | goto fail; |
| | 422 | } |
| | 423 | |
| | 424 | vaDestroyBuffer(ctx->hwctx->display, pic->output_buffer); |
| | 425 | pic->output_buffer = VA_INVALID_ID; |
| | 426 | |
| | 427 | av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n", |
| | 428 | pic->display_order, pic->encode_order); |
| | 429 | return 0; |
| | 430 | |
| | 431 | fail: |
| | 432 | if (pic->output_buffer != VA_INVALID_ID) { |
| | 433 | vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer); |
| | 434 | vaDestroyBuffer(ctx->hwctx->display, pic->output_buffer); |
| | 435 | pic->output_buffer = VA_INVALID_ID; |
| | 436 | } |
| | 437 | return err; |
| | 438 | } |
| | 439 | |
| | 440 | static int vaapi_encode_discard(AVCodecContext *avctx, |
| | 441 | VAAPIEncodePicture *pic) |
| | 442 | { |
| | 443 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 444 | |
| | 445 | vaapi_encode_wait(avctx, pic); |
| | 446 | |
| | 447 | if (pic->output_buffer != VA_INVALID_ID) { |
| | 448 | av_log(avctx, AV_LOG_DEBUG, "Discard output for pic " |
| | 449 | "%"PRId64"/%"PRId64".\n", |
| | 450 | pic->display_order, pic->encode_order); |
| | 451 | |
| | 452 | vaDestroyBuffer(ctx->hwctx->display, pic->output_buffer); |
| | 453 | pic->output_buffer = VA_INVALID_ID; |
| | 454 | } |
| | 455 | |
| | 456 | return 0; |
| | 457 | } |
| | 458 | |
| | 459 | static VAAPIEncodePicture *vaapi_encode_alloc(void) |
| | 460 | { |
| | 461 | VAAPIEncodePicture *pic; |
| | 462 | |
| | 463 | pic = av_mallocz(sizeof(*pic)); |
| | 464 | if (!pic) |
| | 465 | return NULL; |
| | 466 | |
| | 467 | pic->input_surface = VA_INVALID_ID; |
| | 468 | pic->recon_surface = VA_INVALID_ID; |
| | 469 | pic->output_buffer = VA_INVALID_ID; |
| | 470 | |
| | 471 | return pic; |
| | 472 | } |
| | 473 | |
| | 474 | static int vaapi_encode_free(AVCodecContext *avctx, |
| | 475 | VAAPIEncodePicture *pic) |
| | 476 | { |
| | 477 | int i; |
| | 478 | |
| | 479 | if (pic->encode_issued) |
| | 480 | vaapi_encode_discard(avctx, pic); |
| | 481 | |
| | 482 | for (i = 0; i < pic->nb_slices; i++) { |
| | 483 | av_freep(&pic->slices[i]->priv_data); |
| | 484 | av_freep(&pic->slices[i]->codec_slice_params); |
| | 485 | av_freep(&pic->slices[i]); |
| | 486 | } |
| | 487 | av_freep(&pic->codec_picture_params); |
| | 488 | |
| | 489 | av_frame_free(&pic->input_image); |
| | 490 | av_frame_free(&pic->recon_image); |
| | 491 | |
| | 492 | // Output buffer should already be destroyed. |
| | 493 | av_assert0(pic->output_buffer == VA_INVALID_ID); |
| | 494 | |
| | 495 | av_freep(&pic->priv_data); |
| | 496 | av_freep(&pic->codec_picture_params); |
| | 497 | |
| | 498 | av_free(pic); |
| | 499 | |
| | 500 | return 0; |
| | 501 | } |
| | 502 | |
| | 503 | static int vaapi_encode_step(AVCodecContext *avctx, |
| | 504 | VAAPIEncodePicture *target) |
| | 505 | { |
| | 506 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 507 | VAAPIEncodePicture *pic; |
| | 508 | int i, err; |
| | 509 | |
| | 510 | if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING || |
| | 511 | ctx->issue_mode == ISSUE_MODE_MINIMISE_LATENCY) { |
| | 512 | // These two modes are equivalent, except that we wait for |
| | 513 | // immediate completion on each operation if serialised. |
| | 514 | |
| | 515 | if (!target) { |
| | 516 | // No target, nothing to do yet. |
| | 517 | return 0; |
| | 518 | } |
| | 519 | |
| | 520 | if (target->encode_complete) { |
| | 521 | // Already done. |
| | 522 | return 0; |
| | 523 | } |
| | 524 | |
| | 525 | pic = target; |
| | 526 | for (i = 0; i < pic->nb_refs; i++) { |
| | 527 | if (!pic->refs[i]->encode_complete) { |
| | 528 | err = vaapi_encode_step(avctx, pic->refs[i]); |
| | 529 | if (err < 0) |
| | 530 | return err; |
| | 531 | } |
| | 532 | } |
| | 533 | |
| | 534 | err = vaapi_encode_issue(avctx, pic); |
| | 535 | if (err < 0) |
| | 536 | return err; |
| | 537 | |
| | 538 | } else if (ctx->issue_mode == ISSUE_MODE_MAXIMISE_THROUGHPUT) { |
| | 539 | int activity; |
| | 540 | |
| | 541 | do { |
| | 542 | activity = 0; |
| | 543 | for (pic = ctx->pic_start; pic; pic = pic->next) { |
| | 544 | if (!pic->input_available || pic->encode_issued) |
| | 545 | continue; |
| | 546 | for (i = 0; i < pic->nb_refs; i++) { |
| | 547 | if (!pic->refs[i]->encode_issued) |
| | 548 | break; |
| | 549 | } |
| | 550 | if (i < pic->nb_refs) |
| | 551 | continue; |
| | 552 | err = vaapi_encode_issue(avctx, pic); |
| | 553 | if (err < 0) |
| | 554 | return err; |
| | 555 | activity = 1; |
| | 556 | } |
| | 557 | } while(activity); |
| | 558 | |
| | 559 | if (target) { |
| | 560 | av_assert0(target->encode_issued && "broken dependencies?"); |
| | 561 | } |
| | 562 | |
| | 563 | } else { |
| | 564 | av_assert0(0); |
| | 565 | } |
| | 566 | |
| | 567 | return 0; |
| | 568 | } |
| | 569 | |
| | 570 | static int vaapi_encode_get_next(AVCodecContext *avctx, |
| | 571 | VAAPIEncodePicture **pic_out) |
| | 572 | { |
| | 573 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 574 | VAAPIEncodePicture *start, *end, *pic; |
| | 575 | int i; |
| | 576 | |
| | 577 | for (pic = ctx->pic_start; pic; pic = pic->next) { |
| | 578 | if (pic->next) |
| | 579 | av_assert0(pic->display_order + 1 == pic->next->display_order); |
| | 580 | if (pic->display_order == ctx->input_order) { |
| | 581 | *pic_out = pic; |
| | 582 | return 0; |
| | 583 | } |
| | 584 | } |
| | 585 | |
| | 586 | if (ctx->input_order == 0) { |
| | 587 | // First frame is always an IDR frame. |
| | 588 | av_assert0(!ctx->pic_start && !ctx->pic_end); |
| | 589 | |
| | 590 | pic = vaapi_encode_alloc(); |
| | 591 | if (!pic) |
| | 592 | return AVERROR(ENOMEM); |
| | 593 | |
| | 594 | pic->type = PICTURE_TYPE_IDR; |
| | 595 | pic->display_order = 0; |
| | 596 | pic->encode_order = 0; |
| | 597 | |
| | 598 | ctx->pic_start = ctx->pic_end = pic; |
| | 599 | |
| | 600 | *pic_out = pic; |
| | 601 | return 0; |
| | 602 | } |
| | 603 | |
| | 604 | pic = vaapi_encode_alloc(); |
| | 605 | if (!pic) |
| | 606 | return AVERROR(ENOMEM); |
| | 607 | |
| | 608 | if (ctx->p_per_i == 0 || ctx->p_counter == ctx->p_per_i) { |
| | 609 | if (ctx->i_per_idr == 0 || ctx->i_counter == ctx->i_per_idr) { |
| | 610 | pic->type = PICTURE_TYPE_IDR; |
| | 611 | ctx->i_counter = 0; |
| | 612 | } else { |
| | 613 | pic->type = PICTURE_TYPE_I; |
| | 614 | ++ctx->i_counter; |
| | 615 | } |
| | 616 | ctx->p_counter = 0; |
| | 617 | } else { |
| | 618 | pic->type = PICTURE_TYPE_P; |
| | 619 | pic->refs[0] = ctx->pic_end; |
| | 620 | pic->nb_refs = 1; |
| | 621 | ++ctx->p_counter; |
| | 622 | } |
| | 623 | start = end = pic; |
| | 624 | |
| | 625 | if (pic->type != PICTURE_TYPE_IDR) { |
| | 626 | // If that was not an IDR frame, add B frames display-before and |
| | 627 | // encode-after it. |
| | 628 | |
| | 629 | for (i = 0; i < ctx->b_per_p; i++) { |
| | 630 | pic = vaapi_encode_alloc(); |
| | 631 | if (!pic) |
| | 632 | goto fail; |
| | 633 | |
| | 634 | pic->type = PICTURE_TYPE_B; |
| | 635 | pic->refs[0] = ctx->pic_end; |
| | 636 | pic->refs[1] = end; |
| | 637 | pic->nb_refs = 2; |
| | 638 | |
| | 639 | pic->next = start; |
| | 640 | pic->display_order = ctx->input_order + ctx->b_per_p - i - 1; |
| | 641 | pic->encode_order = pic->display_order + 1; |
| | 642 | start = pic; |
| | 643 | } |
| | 644 | } |
| | 645 | |
| | 646 | for (i = 0, pic = start; pic; i++, pic = pic->next) { |
| | 647 | pic->display_order = ctx->input_order + i; |
| | 648 | if (end->type == PICTURE_TYPE_IDR) |
| | 649 | pic->encode_order = ctx->input_order + i; |
| | 650 | else if (pic == end) |
| | 651 | pic->encode_order = ctx->input_order; |
| | 652 | else |
| | 653 | pic->encode_order = ctx->input_order + i + 1; |
| | 654 | } |
| | 655 | |
| | 656 | av_assert0(ctx->pic_end); |
| | 657 | ctx->pic_end->next = start; |
| | 658 | ctx->pic_end = end; |
| | 659 | |
| | 660 | *pic_out = start; |
| | 661 | |
| | 662 | av_log(avctx, AV_LOG_DEBUG, "Pictures:"); |
| | 663 | for (pic = ctx->pic_start; pic; pic = pic->next) { |
| | 664 | av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")", |
| | 665 | picture_type_name[pic->type], |
| | 666 | pic->display_order, pic->encode_order); |
| | 667 | } |
| | 668 | av_log(avctx, AV_LOG_DEBUG, "\n"); |
| | 669 | |
| | 670 | return 0; |
| | 671 | |
| | 672 | fail: |
| | 673 | while (start) { |
| | 674 | pic = start->next; |
| | 675 | vaapi_encode_free(avctx, start); |
| | 676 | start = pic; |
| | 677 | } |
| | 678 | return AVERROR(ENOMEM); |
| | 679 | } |
| | 680 | |
| | 681 | static int vaapi_encode_mangle_end(AVCodecContext *avctx) |
| | 682 | { |
| | 683 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 684 | VAAPIEncodePicture *pic, *last_pic, *next; |
| | 685 | |
| | 686 | // Find the last picture we actually have input for. |
| | 687 | for (pic = ctx->pic_start; pic; pic = pic->next) { |
| | 688 | if (!pic->input_available) |
| | 689 | break; |
| | 690 | last_pic = pic; |
| | 691 | } |
| | 692 | |
| | 693 | if (pic) { |
| | 694 | av_assert0(last_pic); |
| | 695 | |
| | 696 | if (last_pic->type == PICTURE_TYPE_B) { |
| | 697 | // Some fixing up is required. Change the type of this |
| | 698 | // picture to P, then modify preceeding B references which |
| | 699 | // point beyond it to point at it instead. |
| | 700 | |
| | 701 | last_pic->type = PICTURE_TYPE_P; |
| | 702 | last_pic->encode_order = last_pic->refs[1]->encode_order; |
| | 703 | |
| | 704 | for (pic = ctx->pic_start; pic != last_pic; pic = pic->next) { |
| | 705 | if (pic->type == PICTURE_TYPE_B && |
| | 706 | pic->refs[1] == last_pic->refs[1]) |
| | 707 | pic->refs[1] = last_pic; |
| | 708 | } |
| | 709 | |
| | 710 | last_pic->nb_refs = 1; |
| | 711 | last_pic->refs[1] = NULL; |
| | 712 | } else { |
| | 713 | // We can use the current structure (no references point |
| | 714 | // beyond the end), but there are unused pics to discard. |
| | 715 | } |
| | 716 | |
| | 717 | // Discard all following pics, they will never be used. |
| | 718 | for (pic = last_pic->next; pic; pic = next) { |
| | 719 | next = pic->next; |
| | 720 | vaapi_encode_free(avctx, pic); |
| | 721 | } |
| | 722 | |
| | 723 | last_pic->next = NULL; |
| | 724 | ctx->pic_end = last_pic; |
| | 725 | |
| | 726 | } else { |
| | 727 | // Input is available for all pictures, so we don't need to |
| | 728 | // mangle anything. |
| | 729 | } |
| | 730 | |
| | 731 | av_log(avctx, AV_LOG_DEBUG, "Pictures at end of stream:"); |
| | 732 | for (pic = ctx->pic_start; pic; pic = pic->next) { |
| | 733 | av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")", |
| | 734 | picture_type_name[pic->type], |
| | 735 | pic->display_order, pic->encode_order); |
| | 736 | } |
| | 737 | av_log(avctx, AV_LOG_DEBUG, "\n"); |
| | 738 | |
| | 739 | return 0; |
| | 740 | } |
| | 741 | |
| | 742 | static int vaapi_encode_clear_old(AVCodecContext *avctx) |
| | 743 | { |
| | 744 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 745 | VAAPIEncodePicture *pic, *old; |
| | 746 | int i; |
| | 747 | |
| | 748 | while (ctx->pic_start != ctx->pic_end) { |
| | 749 | old = ctx->pic_start; |
| | 750 | if (old->encode_order > ctx->output_order) |
| | 751 | break; |
| | 752 | |
| | 753 | for (pic = old->next; pic; pic = pic->next) { |
| | 754 | if (pic->encode_complete) |
| | 755 | continue; |
| | 756 | for (i = 0; i < pic->nb_refs; i++) { |
| | 757 | if (pic->refs[i] == old) { |
| | 758 | // We still need this picture because it's referred to |
| | 759 | // directly by a later one, so it and all following |
| | 760 | // pictures have to stay. |
| | 761 | return 0; |
| | 762 | } |
| | 763 | } |
| | 764 | } |
| | 765 | |
| | 766 | pic = ctx->pic_start; |
| | 767 | ctx->pic_start = pic->next; |
| | 768 | vaapi_encode_free(avctx, pic); |
| | 769 | } |
| | 770 | |
| | 771 | return 0; |
| | 772 | } |
| | 773 | |
| | 774 | int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt, |
| | 775 | const AVFrame *input_image, int *got_packet) |
| | 776 | { |
| | 777 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 778 | VAAPIEncodePicture *pic; |
| | 779 | int err; |
| | 780 | |
| | 781 | if (input_image) { |
| | 782 | av_log(avctx, AV_LOG_DEBUG, "Encode frame: %ux%u (%"PRId64").\n", |
| | 783 | input_image->width, input_image->height, input_image->pts); |
| | 784 | |
| | 785 | err = vaapi_encode_get_next(avctx, &pic); |
| | 786 | if (err) { |
| | 787 | av_log(avctx, AV_LOG_ERROR, "Input setup failed: %d.\n", err); |
| | 788 | return err; |
| | 789 | } |
| | 790 | |
| | 791 | pic->input_image = av_frame_alloc(); |
| | 792 | if (!pic->input_image) { |
| | 793 | err = AVERROR(ENOMEM); |
| | 794 | goto fail; |
| | 795 | } |
| | 796 | err = av_frame_ref(pic->input_image, input_image); |
| | 797 | if (err < 0) |
| | 798 | goto fail; |
| | 799 | pic->input_surface = (VASurfaceID)(uintptr_t)input_image->data[3]; |
| | 800 | pic->pts = input_image->pts; |
| | 801 | |
| | 802 | if (ctx->input_order == 0) |
| | 803 | ctx->first_pts = pic->pts; |
| | 804 | if (ctx->input_order == ctx->decode_delay) |
| | 805 | ctx->dts_pts_diff = pic->pts - ctx->first_pts; |
| | 806 | if (ctx->output_delay > 0) |
| | 807 | ctx->ts_ring[ctx->input_order % (3 * ctx->output_delay)] = pic->pts; |
| | 808 | |
| | 809 | pic->input_available = 1; |
| | 810 | |
| | 811 | } else { |
| | 812 | if (!ctx->end_of_stream) { |
| | 813 | err = vaapi_encode_mangle_end(avctx); |
| | 814 | if (err < 0) |
| | 815 | goto fail; |
| | 816 | ctx->end_of_stream = 1; |
| | 817 | } |
| | 818 | } |
| | 819 | |
| | 820 | ++ctx->input_order; |
| | 821 | ++ctx->output_order; |
| | 822 | av_assert0(ctx->output_order + ctx->output_delay + 1 == ctx->input_order); |
| | 823 | |
| | 824 | for (pic = ctx->pic_start; pic; pic = pic->next) |
| | 825 | if (pic->encode_order == ctx->output_order) |
| | 826 | break; |
| | 827 | |
| | 828 | // pic can be null here if we don't have a specific target in this |
| | 829 | // iteration. We might still issue encodes if things can be overlapped, |
| | 830 | // even though we don't intend to output anything. |
| | 831 | |
| | 832 | err = vaapi_encode_step(avctx, pic); |
| | 833 | if (err < 0) { |
| | 834 | av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); |
| | 835 | goto fail; |
| | 836 | } |
| | 837 | |
| | 838 | if (!pic) { |
| | 839 | *got_packet = 0; |
| | 840 | } else { |
| | 841 | err = vaapi_encode_output(avctx, pic, pkt); |
| | 842 | if (err < 0) { |
| | 843 | av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err); |
| | 844 | goto fail; |
| | 845 | } |
| | 846 | |
| | 847 | if (ctx->output_delay == 0) { |
| | 848 | pkt->dts = pkt->pts; |
| | 849 | } else if (ctx->output_order < ctx->decode_delay) { |
| | 850 | if (ctx->ts_ring[ctx->output_order] < INT64_MIN + ctx->dts_pts_diff) |
| | 851 | pkt->dts = INT64_MIN; |
| | 852 | else |
| | 853 | pkt->dts = ctx->ts_ring[ctx->output_order] - ctx->dts_pts_diff; |
| | 854 | } else { |
| | 855 | pkt->dts = ctx->ts_ring[(ctx->output_order - ctx->decode_delay) % |
| | 856 | (3 * ctx->output_delay)]; |
| | 857 | } |
| | 858 | |
| | 859 | *got_packet = 1; |
| | 860 | } |
| | 861 | |
| | 862 | err = vaapi_encode_clear_old(avctx); |
| | 863 | if (err < 0) { |
| | 864 | av_log(avctx, AV_LOG_ERROR, "List clearing failed: %d.\n", err); |
| | 865 | goto fail; |
| | 866 | } |
| | 867 | |
| | 868 | return 0; |
| | 869 | |
| | 870 | fail: |
| | 871 | // Unclear what to clean up on failure. There are probably some things we |
| | 872 | // could do usefully clean up here, but for now just leave them for uninit() |
| | 873 | // to do instead. |
| | 874 | return err; |
| | 875 | } |
| | 876 | |
| | 877 | av_cold int ff_vaapi_encode_init(AVCodecContext *avctx, |
| | 878 | const VAAPIEncodeType *type) |
| | 879 | { |
| | 880 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 881 | AVVAAPIFramesContext *recon_hwctx = NULL; |
| | 882 | AVVAAPIHWConfig *hwconfig = NULL; |
| | 883 | AVHWFramesConstraints *constraints = NULL; |
| | 884 | enum AVPixelFormat recon_format; |
| | 885 | VAStatus vas; |
| | 886 | int err, i; |
| | 887 | |
| | 888 | if (!avctx->hw_frames_ctx) { |
| | 889 | av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " |
| | 890 | "required to associate the encoding device.\n"); |
| | 891 | return AVERROR(EINVAL); |
| | 892 | } |
| | 893 | |
| | 894 | ctx->codec = type; |
| | 895 | |
| | 896 | ctx->priv_data = av_mallocz(type->priv_data_size); |
| | 897 | if (!ctx->priv_data) { |
| | 898 | err = AVERROR(ENOMEM); |
| | 899 | goto fail; |
| | 900 | } |
| | 901 | |
| | 902 | ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); |
| | 903 | if (!ctx->input_frames_ref) { |
| | 904 | err = AVERROR(ENOMEM); |
| | 905 | goto fail; |
| | 906 | } |
| | 907 | ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; |
| | 908 | |
| | 909 | ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); |
| | 910 | if (!ctx->device_ref) { |
| | 911 | err = AVERROR(ENOMEM); |
| | 912 | goto fail; |
| | 913 | } |
| | 914 | ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; |
| | 915 | ctx->hwctx = ctx->device->hwctx; |
| | 916 | |
| | 917 | err = ctx->codec->init(avctx); |
| | 918 | if (err < 0) |
| | 919 | goto fail; |
| | 920 | |
| | 921 | vas = vaCreateConfig(ctx->hwctx->display, |
| | 922 | ctx->va_profile, ctx->va_entrypoint, |
| | 923 | ctx->config_attributes, ctx->nb_config_attributes, |
| | 924 | &ctx->va_config); |
| | 925 | if (vas != VA_STATUS_SUCCESS) { |
| | 926 | av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline " |
| | 927 | "configuration: %d (%s).\n", vas, vaErrorStr(vas)); |
| | 928 | err = AVERROR(EIO); |
| | 929 | goto fail; |
| | 930 | } |
| | 931 | |
| | 932 | hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); |
| | 933 | if (!hwconfig) { |
| | 934 | err = AVERROR(ENOMEM); |
| | 935 | goto fail; |
| | 936 | } |
| | 937 | hwconfig->config_id = ctx->va_config; |
| | 938 | |
| | 939 | constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, |
| | 940 | hwconfig); |
| | 941 | if (!constraints) { |
| | 942 | err = AVERROR(ENOMEM); |
| | 943 | goto fail; |
| | 944 | } |
| | 945 | |
| | 946 | // Probably we can use the input surface format as the surface format |
| | 947 | // of the reconstructed frames. If not, we just pick the first (only?) |
| | 948 | // format in the valid list and hope that it all works. |
| | 949 | recon_format = AV_PIX_FMT_NONE; |
| | 950 | if (constraints->valid_sw_formats) { |
| | 951 | for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { |
| | 952 | if (ctx->input_frames->sw_format == |
| | 953 | constraints->valid_sw_formats[i]) { |
| | 954 | recon_format = ctx->input_frames->sw_format; |
| | 955 | break; |
| | 956 | } |
| | 957 | } |
| | 958 | if (recon_format == AV_PIX_FMT_NONE) |
| | 959 | recon_format = constraints->valid_sw_formats[i]; |
| | 960 | } else { |
| | 961 | // No idea what to use; copy input format. |
| | 962 | recon_format = ctx->input_frames->sw_format; |
| | 963 | } |
| | 964 | av_log(avctx, AV_LOG_DEBUG, "Using %s as format of " |
| | 965 | "reconstructed frames.\n", av_get_pix_fmt_name(recon_format)); |
| | 966 | |
| | 967 | if (ctx->aligned_width < constraints->min_width || |
| | 968 | ctx->aligned_height < constraints->min_height || |
| | 969 | ctx->aligned_width > constraints->max_width || |
| | 970 | ctx->aligned_height > constraints->max_height) { |
| | 971 | av_log(avctx, AV_LOG_ERROR, "Hardware does not support encoding at " |
| | 972 | "size %dx%d (constraints: width %d-%d height %d-%d).\n", |
| | 973 | ctx->aligned_width, ctx->aligned_height, |
| | 974 | constraints->min_width, constraints->max_width, |
| | 975 | constraints->min_height, constraints->max_height); |
| | 976 | err = AVERROR(EINVAL); |
| | 977 | goto fail; |
| | 978 | } |
| | 979 | |
| | 980 | av_freep(&hwconfig); |
| | 981 | av_hwframe_constraints_free(&constraints); |
| | 982 | |
| | 983 | ctx->recon_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); |
| | 984 | if (!ctx->recon_frames_ref) { |
| | 985 | err = AVERROR(ENOMEM); |
| | 986 | goto fail; |
| | 987 | } |
| | 988 | ctx->recon_frames = (AVHWFramesContext*)ctx->recon_frames_ref->data; |
| | 989 | |
| | 990 | ctx->recon_frames->format = AV_PIX_FMT_VAAPI; |
| | 991 | ctx->recon_frames->sw_format = recon_format; |
| | 992 | ctx->recon_frames->width = ctx->aligned_width; |
| | 993 | ctx->recon_frames->height = ctx->aligned_height; |
| | 994 | ctx->recon_frames->initial_pool_size = ctx->nb_recon_frames; |
| | 995 | |
| | 996 | err = av_hwframe_ctx_init(ctx->recon_frames_ref); |
| | 997 | if (err < 0) { |
| | 998 | av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed " |
| | 999 | "frame context: %d.\n", err); |
| | 1000 | goto fail; |
| | 1001 | } |
| | 1002 | recon_hwctx = ctx->recon_frames->hwctx; |
| | 1003 | |
| | 1004 | vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, |
| | 1005 | ctx->aligned_width, ctx->aligned_height, |
| | 1006 | VA_PROGRESSIVE, |
| | 1007 | recon_hwctx->surface_ids, |
| | 1008 | recon_hwctx->nb_surfaces, |
| | 1009 | &ctx->va_context); |
| | 1010 | if (vas != VA_STATUS_SUCCESS) { |
| | 1011 | av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline " |
| | 1012 | "context: %d (%s).\n", vas, vaErrorStr(vas)); |
| | 1013 | err = AVERROR(EIO); |
| | 1014 | goto fail; |
| | 1015 | } |
| | 1016 | |
| | 1017 | ctx->input_order = 0; |
| | 1018 | ctx->output_delay = avctx->max_b_frames; |
| | 1019 | ctx->decode_delay = 1; |
| | 1020 | ctx->output_order = - ctx->output_delay - 1; |
| | 1021 | |
| | 1022 | if (ctx->codec->sequence_params_size > 0) { |
| | 1023 | ctx->codec_sequence_params = |
| | 1024 | av_mallocz(ctx->codec->sequence_params_size); |
| | 1025 | if (!ctx->codec_sequence_params) { |
| | 1026 | err = AVERROR(ENOMEM); |
| | 1027 | goto fail; |
| | 1028 | } |
| | 1029 | } |
| | 1030 | if (ctx->codec->picture_params_size > 0) { |
| | 1031 | ctx->codec_picture_params = |
| | 1032 | av_mallocz(ctx->codec->picture_params_size); |
| | 1033 | if (!ctx->codec_picture_params) { |
| | 1034 | err = AVERROR(ENOMEM); |
| | 1035 | goto fail; |
| | 1036 | } |
| | 1037 | } |
| | 1038 | |
| | 1039 | if (ctx->codec->init_sequence_params) { |
| | 1040 | err = ctx->codec->init_sequence_params(avctx); |
| | 1041 | if (err < 0) { |
| | 1042 | av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation " |
| | 1043 | "failed: %d.\n", err); |
| | 1044 | goto fail; |
| | 1045 | } |
| | 1046 | } |
| | 1047 | |
| | 1048 | // All I are IDR for now. |
| | 1049 | ctx->i_per_idr = 0; |
| | 1050 | ctx->p_per_i = ((avctx->gop_size + avctx->max_b_frames) / |
| | 1051 | (avctx->max_b_frames + 1)); |
| | 1052 | ctx->b_per_p = avctx->max_b_frames; |
| | 1053 | |
| | 1054 | // This should be configurable somehow. (Needs testing on a machine |
| | 1055 | // where it actually overlaps properly, though.) |
| | 1056 | ctx->issue_mode = ISSUE_MODE_MAXIMISE_THROUGHPUT; |
| | 1057 | |
| | 1058 | return 0; |
| | 1059 | |
| | 1060 | fail: |
| | 1061 | av_freep(&hwconfig); |
| | 1062 | av_hwframe_constraints_free(&constraints); |
| | 1063 | ff_vaapi_encode_close(avctx); |
| | 1064 | return err; |
| | 1065 | } |
| | 1066 | |
| | 1067 | av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) |
| | 1068 | { |
| | 1069 | VAAPIEncodeContext *ctx = avctx->priv_data; |
| | 1070 | VAAPIEncodePicture *pic, *next; |
| | 1071 | |
| | 1072 | for (pic = ctx->pic_start; pic; pic = next) { |
| | 1073 | next = pic->next; |
| | 1074 | vaapi_encode_free(avctx, pic); |
| | 1075 | } |
| | 1076 | |
| | 1077 | if (ctx->va_context != VA_INVALID_ID) |
| | 1078 | vaDestroyContext(ctx->hwctx->display, ctx->va_context); |
| | 1079 | |
| | 1080 | if (ctx->va_config != VA_INVALID_ID) |
| | 1081 | vaDestroyConfig(ctx->hwctx->display, ctx->va_config); |
| | 1082 | |
| | 1083 | if (ctx->codec->close) |
| | 1084 | ctx->codec->close(avctx); |
| | 1085 | |
| | 1086 | av_freep(&ctx->codec_sequence_params); |
| | 1087 | av_freep(&ctx->codec_picture_params); |
| | 1088 | |
| | 1089 | av_buffer_unref(&ctx->recon_frames_ref); |
| | 1090 | av_buffer_unref(&ctx->input_frames_ref); |
| | 1091 | av_buffer_unref(&ctx->device_ref); |
| | 1092 | |
| | 1093 | av_freep(&ctx->priv_data); |
| | 1094 | |
| | 1095 | return 0; |
| | 1096 | } |