Commit | Line | Data |
---|---|---|
104c804b MT |
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" | |
2bfa067d | 23 | #include "libavutil/common.h" |
104c804b MT |
24 | #include "libavutil/log.h" |
25 | #include "libavutil/pixdesc.h" | |
26 | ||
27 | #include "vaapi_encode.h" | |
28 | #include "avcodec.h" | |
29 | ||
30 | static const char *picture_type_name[] = { "IDR", "I", "P", "B" }; | |
31 | ||
32 | static int vaapi_encode_make_packed_header(AVCodecContext *avctx, | |
33 | VAAPIEncodePicture *pic, | |
34 | int type, char *data, size_t bit_len) | |
35 | { | |
36 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
37 | VAStatus vas; | |
38 | VABufferID param_buffer, data_buffer; | |
39 | VAEncPackedHeaderParameterBuffer params = { | |
40 | .type = type, | |
41 | .bit_length = bit_len, | |
42 | .has_emulation_bytes = 1, | |
43 | }; | |
44 | ||
45 | av_assert0(pic->nb_param_buffers + 2 <= MAX_PARAM_BUFFERS); | |
46 | ||
47 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
48 | VAEncPackedHeaderParameterBufferType, | |
49 | sizeof(params), 1, ¶ms, ¶m_buffer); | |
50 | if (vas != VA_STATUS_SUCCESS) { | |
51 | av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " | |
52 | "for packed header (type %d): %d (%s).\n", | |
53 | type, vas, vaErrorStr(vas)); | |
54 | return AVERROR(EIO); | |
55 | } | |
56 | pic->param_buffers[pic->nb_param_buffers++] = param_buffer; | |
57 | ||
58 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
59 | VAEncPackedHeaderDataBufferType, | |
60 | (bit_len + 7) / 8, 1, data, &data_buffer); | |
61 | if (vas != VA_STATUS_SUCCESS) { | |
62 | av_log(avctx, AV_LOG_ERROR, "Failed to create data buffer " | |
63 | "for packed header (type %d): %d (%s).\n", | |
64 | type, vas, vaErrorStr(vas)); | |
65 | return AVERROR(EIO); | |
66 | } | |
67 | pic->param_buffers[pic->nb_param_buffers++] = data_buffer; | |
68 | ||
69 | av_log(avctx, AV_LOG_DEBUG, "Packed header buffer (%d) is %#x/%#x " | |
70 | "(%zu bits).\n", type, param_buffer, data_buffer, bit_len); | |
71 | return 0; | |
72 | } | |
73 | ||
74 | static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, | |
75 | VAAPIEncodePicture *pic, | |
76 | int type, char *data, size_t len) | |
77 | { | |
78 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
79 | VAStatus vas; | |
80 | VABufferID buffer; | |
81 | ||
82 | av_assert0(pic->nb_param_buffers + 1 <= MAX_PARAM_BUFFERS); | |
83 | ||
84 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
85 | type, len, 1, data, &buffer); | |
86 | if (vas != VA_STATUS_SUCCESS) { | |
87 | av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer " | |
88 | "(type %d): %d (%s).\n", type, vas, vaErrorStr(vas)); | |
89 | return AVERROR(EIO); | |
90 | } | |
91 | pic->param_buffers[pic->nb_param_buffers++] = buffer; | |
92 | ||
93 | av_log(avctx, AV_LOG_DEBUG, "Param buffer (%d) is %#x.\n", | |
94 | type, buffer); | |
95 | return 0; | |
96 | } | |
97 | ||
98 | static int vaapi_encode_wait(AVCodecContext *avctx, | |
99 | VAAPIEncodePicture *pic) | |
100 | { | |
101 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
102 | VAStatus vas; | |
103 | ||
104 | av_assert0(pic->encode_issued); | |
105 | ||
106 | if (pic->encode_complete) { | |
107 | // Already waited for this picture. | |
108 | return 0; | |
109 | } | |
110 | ||
111 | av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" " | |
112 | "(recon surface %#x).\n", pic->display_order, | |
113 | pic->encode_order, pic->recon_surface); | |
114 | ||
115 | vas = vaSyncSurface(ctx->hwctx->display, pic->recon_surface); | |
116 | if (vas != VA_STATUS_SUCCESS) { | |
117 | av_log(avctx, AV_LOG_ERROR, "Failed to sync to picture completion: " | |
118 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
119 | return AVERROR(EIO); | |
120 | } | |
121 | ||
122 | // Input is definitely finished with now. | |
123 | av_frame_free(&pic->input_image); | |
124 | ||
125 | pic->encode_complete = 1; | |
126 | return 0; | |
127 | } | |
128 | ||
129 | static int vaapi_encode_issue(AVCodecContext *avctx, | |
130 | VAAPIEncodePicture *pic) | |
131 | { | |
132 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
133 | VAAPIEncodeSlice *slice; | |
134 | VAStatus vas; | |
135 | int err, i; | |
136 | char data[MAX_PARAM_BUFFER_SIZE]; | |
137 | size_t bit_len; | |
138 | ||
139 | av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " | |
140 | "as type %s.\n", pic->display_order, pic->encode_order, | |
141 | picture_type_name[pic->type]); | |
142 | if (pic->nb_refs == 0) { | |
143 | av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n"); | |
144 | } else { | |
145 | av_log(avctx, AV_LOG_DEBUG, "Refers to:"); | |
146 | for (i = 0; i < pic->nb_refs; i++) { | |
147 | av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, | |
148 | pic->refs[i]->display_order, pic->refs[i]->encode_order); | |
149 | } | |
150 | av_log(avctx, AV_LOG_DEBUG, ".\n"); | |
151 | } | |
152 | ||
153 | av_assert0(pic->input_available && !pic->encode_issued); | |
154 | for (i = 0; i < pic->nb_refs; i++) { | |
155 | av_assert0(pic->refs[i]); | |
156 | // If we are serialised then the references must have already | |
157 | // completed. If not, they must have been issued but need not | |
158 | // have completed yet. | |
159 | if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING) | |
160 | av_assert0(pic->refs[i]->encode_complete); | |
161 | else | |
162 | av_assert0(pic->refs[i]->encode_issued); | |
163 | } | |
164 | ||
165 | av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface); | |
166 | ||
167 | pic->recon_image = av_frame_alloc(); | |
168 | if (!pic->recon_image) { | |
169 | err = AVERROR(ENOMEM); | |
170 | goto fail; | |
171 | } | |
172 | ||
173 | err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0); | |
174 | if (err < 0) { | |
175 | err = AVERROR(ENOMEM); | |
176 | goto fail; | |
177 | } | |
178 | pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3]; | |
179 | av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface); | |
180 | ||
8a62d2c2 MT |
181 | pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool); |
182 | if (!pic->output_buffer_ref) { | |
104c804b MT |
183 | err = AVERROR(ENOMEM); |
184 | goto fail; | |
185 | } | |
8a62d2c2 | 186 | pic->output_buffer = (VABufferID)(uintptr_t)pic->output_buffer_ref->data; |
104c804b MT |
187 | av_log(avctx, AV_LOG_DEBUG, "Output buffer is %#x.\n", |
188 | pic->output_buffer); | |
189 | ||
190 | if (ctx->codec->picture_params_size > 0) { | |
191 | pic->codec_picture_params = av_malloc(ctx->codec->picture_params_size); | |
192 | if (!pic->codec_picture_params) | |
193 | goto fail; | |
194 | memcpy(pic->codec_picture_params, ctx->codec_picture_params, | |
195 | ctx->codec->picture_params_size); | |
196 | } else { | |
197 | av_assert0(!ctx->codec_picture_params); | |
198 | } | |
199 | ||
200 | pic->nb_param_buffers = 0; | |
201 | ||
f6b85523 MT |
202 | if (pic->encode_order == 0) { |
203 | // Global parameter buffers are set on the first picture only. | |
204 | ||
205 | for (i = 0; i < ctx->nb_global_params; i++) { | |
206 | err = vaapi_encode_make_param_buffer(avctx, pic, | |
207 | VAEncMiscParameterBufferType, | |
208 | (char*)ctx->global_params[i], | |
209 | ctx->global_params_size[i]); | |
210 | if (err < 0) | |
211 | goto fail; | |
212 | } | |
213 | } | |
214 | ||
104c804b MT |
215 | if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { |
216 | err = vaapi_encode_make_param_buffer(avctx, pic, | |
217 | VAEncSequenceParameterBufferType, | |
218 | ctx->codec_sequence_params, | |
219 | ctx->codec->sequence_params_size); | |
220 | if (err < 0) | |
221 | goto fail; | |
222 | } | |
223 | ||
224 | if (ctx->codec->init_picture_params) { | |
225 | err = ctx->codec->init_picture_params(avctx, pic); | |
226 | if (err < 0) { | |
227 | av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture " | |
228 | "parameters: %d.\n", err); | |
229 | goto fail; | |
230 | } | |
231 | err = vaapi_encode_make_param_buffer(avctx, pic, | |
232 | VAEncPictureParameterBufferType, | |
233 | pic->codec_picture_params, | |
234 | ctx->codec->picture_params_size); | |
235 | if (err < 0) | |
236 | goto fail; | |
237 | } | |
238 | ||
239 | if (pic->type == PICTURE_TYPE_IDR) { | |
892bbbcd MT |
240 | if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE && |
241 | ctx->codec->write_sequence_header) { | |
104c804b MT |
242 | bit_len = 8 * sizeof(data); |
243 | err = ctx->codec->write_sequence_header(avctx, data, &bit_len); | |
244 | if (err < 0) { | |
245 | av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence " | |
246 | "header: %d.\n", err); | |
247 | goto fail; | |
248 | } | |
249 | err = vaapi_encode_make_packed_header(avctx, pic, | |
250 | ctx->codec->sequence_header_type, | |
251 | data, bit_len); | |
252 | if (err < 0) | |
253 | goto fail; | |
254 | } | |
255 | } | |
256 | ||
892bbbcd MT |
257 | if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_PICTURE && |
258 | ctx->codec->write_picture_header) { | |
104c804b MT |
259 | bit_len = 8 * sizeof(data); |
260 | err = ctx->codec->write_picture_header(avctx, pic, data, &bit_len); | |
261 | if (err < 0) { | |
262 | av_log(avctx, AV_LOG_ERROR, "Failed to write per-picture " | |
263 | "header: %d.\n", err); | |
264 | goto fail; | |
265 | } | |
266 | err = vaapi_encode_make_packed_header(avctx, pic, | |
267 | ctx->codec->picture_header_type, | |
268 | data, bit_len); | |
269 | if (err < 0) | |
270 | goto fail; | |
271 | } | |
272 | ||
273 | if (ctx->codec->write_extra_buffer) { | |
274 | for (i = 0;; i++) { | |
275 | size_t len = sizeof(data); | |
276 | int type; | |
277 | err = ctx->codec->write_extra_buffer(avctx, pic, i, &type, | |
278 | data, &len); | |
279 | if (err == AVERROR_EOF) | |
280 | break; | |
281 | if (err < 0) { | |
282 | av_log(avctx, AV_LOG_ERROR, "Failed to write extra " | |
283 | "buffer %d: %d.\n", i, err); | |
284 | goto fail; | |
285 | } | |
286 | ||
287 | err = vaapi_encode_make_param_buffer(avctx, pic, type, | |
288 | data, len); | |
289 | if (err < 0) | |
290 | goto fail; | |
291 | } | |
292 | } | |
293 | ||
892bbbcd MT |
294 | if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_MISC && |
295 | ctx->codec->write_extra_header) { | |
19d7667a MT |
296 | for (i = 0;; i++) { |
297 | int type; | |
298 | bit_len = 8 * sizeof(data); | |
299 | err = ctx->codec->write_extra_header(avctx, pic, i, &type, | |
300 | data, &bit_len); | |
301 | if (err == AVERROR_EOF) | |
302 | break; | |
303 | if (err < 0) { | |
304 | av_log(avctx, AV_LOG_ERROR, "Failed to write extra " | |
305 | "header %d: %d.\n", i, err); | |
306 | goto fail; | |
307 | } | |
308 | ||
309 | err = vaapi_encode_make_packed_header(avctx, pic, type, | |
310 | data, bit_len); | |
311 | if (err < 0) | |
312 | goto fail; | |
313 | } | |
314 | } | |
315 | ||
104c804b MT |
316 | av_assert0(pic->nb_slices <= MAX_PICTURE_SLICES); |
317 | for (i = 0; i < pic->nb_slices; i++) { | |
318 | slice = av_mallocz(sizeof(*slice)); | |
319 | if (!slice) { | |
320 | err = AVERROR(ENOMEM); | |
321 | goto fail; | |
322 | } | |
323 | pic->slices[i] = slice; | |
324 | ||
325 | if (ctx->codec->slice_params_size > 0) { | |
326 | slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); | |
327 | if (!slice->codec_slice_params) { | |
328 | err = AVERROR(ENOMEM); | |
329 | goto fail; | |
330 | } | |
331 | } | |
332 | ||
333 | if (ctx->codec->init_slice_params) { | |
334 | err = ctx->codec->init_slice_params(avctx, pic, slice); | |
335 | if (err < 0) { | |
336 | av_log(avctx, AV_LOG_ERROR, "Failed to initalise slice " | |
337 | "parameters: %d.\n", err); | |
338 | goto fail; | |
339 | } | |
340 | } | |
341 | ||
892bbbcd MT |
342 | if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SLICE && |
343 | ctx->codec->write_slice_header) { | |
104c804b MT |
344 | bit_len = 8 * sizeof(data); |
345 | err = ctx->codec->write_slice_header(avctx, pic, slice, | |
346 | data, &bit_len); | |
347 | if (err < 0) { | |
348 | av_log(avctx, AV_LOG_ERROR, "Failed to write per-slice " | |
349 | "header: %d.\n", err); | |
350 | goto fail; | |
351 | } | |
352 | err = vaapi_encode_make_packed_header(avctx, pic, | |
353 | ctx->codec->slice_header_type, | |
354 | data, bit_len); | |
355 | if (err < 0) | |
356 | goto fail; | |
357 | } | |
358 | ||
359 | if (ctx->codec->init_slice_params) { | |
360 | err = vaapi_encode_make_param_buffer(avctx, pic, | |
361 | VAEncSliceParameterBufferType, | |
362 | slice->codec_slice_params, | |
363 | ctx->codec->slice_params_size); | |
364 | if (err < 0) | |
365 | goto fail; | |
366 | } | |
367 | } | |
368 | ||
369 | vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, | |
370 | pic->input_surface); | |
371 | if (vas != VA_STATUS_SUCCESS) { | |
372 | av_log(avctx, AV_LOG_ERROR, "Failed to begin picture encode issue: " | |
373 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
374 | err = AVERROR(EIO); | |
375 | goto fail_with_picture; | |
376 | } | |
377 | ||
378 | vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, | |
379 | pic->param_buffers, pic->nb_param_buffers); | |
380 | if (vas != VA_STATUS_SUCCESS) { | |
381 | av_log(avctx, AV_LOG_ERROR, "Failed to upload encode parameters: " | |
382 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
383 | err = AVERROR(EIO); | |
384 | goto fail_with_picture; | |
385 | } | |
386 | ||
387 | vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); | |
388 | if (vas != VA_STATUS_SUCCESS) { | |
389 | av_log(avctx, AV_LOG_ERROR, "Failed to end picture encode issue: " | |
390 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
391 | err = AVERROR(EIO); | |
221ffca6 MT |
392 | // vaRenderPicture() has been called here, so we should not destroy |
393 | // the parameter buffers unless separate destruction is required. | |
394 | if (ctx->hwctx->driver_quirks & | |
395 | AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) | |
396 | goto fail; | |
397 | else | |
398 | goto fail_at_end; | |
399 | } | |
400 | ||
401 | if (ctx->hwctx->driver_quirks & | |
402 | AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) { | |
403 | for (i = 0; i < pic->nb_param_buffers; i++) { | |
404 | vas = vaDestroyBuffer(ctx->hwctx->display, | |
405 | pic->param_buffers[i]); | |
406 | if (vas != VA_STATUS_SUCCESS) { | |
407 | av_log(avctx, AV_LOG_ERROR, "Failed to destroy " | |
408 | "param buffer %#x: %d (%s).\n", | |
409 | pic->param_buffers[i], vas, vaErrorStr(vas)); | |
410 | // And ignore. | |
411 | } | |
412 | } | |
104c804b MT |
413 | } |
414 | ||
415 | pic->encode_issued = 1; | |
416 | ||
417 | if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING) | |
418 | return vaapi_encode_wait(avctx, pic); | |
419 | else | |
420 | return 0; | |
421 | ||
422 | fail_with_picture: | |
423 | vaEndPicture(ctx->hwctx->display, ctx->va_context); | |
424 | fail: | |
425 | for(i = 0; i < pic->nb_param_buffers; i++) | |
426 | vaDestroyBuffer(ctx->hwctx->display, pic->param_buffers[i]); | |
427 | fail_at_end: | |
428 | av_freep(&pic->codec_picture_params); | |
429 | av_frame_free(&pic->recon_image); | |
430 | return err; | |
431 | } | |
432 | ||
433 | static int vaapi_encode_output(AVCodecContext *avctx, | |
434 | VAAPIEncodePicture *pic, AVPacket *pkt) | |
435 | { | |
436 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
437 | VACodedBufferSegment *buf_list, *buf; | |
438 | VAStatus vas; | |
439 | int err; | |
440 | ||
441 | err = vaapi_encode_wait(avctx, pic); | |
442 | if (err < 0) | |
443 | return err; | |
444 | ||
445 | buf_list = NULL; | |
446 | vas = vaMapBuffer(ctx->hwctx->display, pic->output_buffer, | |
447 | (void**)&buf_list); | |
448 | if (vas != VA_STATUS_SUCCESS) { | |
449 | av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: " | |
450 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
451 | err = AVERROR(EIO); | |
452 | goto fail; | |
453 | } | |
454 | ||
455 | for (buf = buf_list; buf; buf = buf->next) { | |
456 | av_log(avctx, AV_LOG_DEBUG, "Output buffer: %u bytes " | |
457 | "(status %08x).\n", buf->size, buf->status); | |
458 | ||
459 | err = av_new_packet(pkt, buf->size); | |
460 | if (err < 0) | |
8a62d2c2 | 461 | goto fail_mapped; |
104c804b MT |
462 | |
463 | memcpy(pkt->data, buf->buf, buf->size); | |
464 | } | |
465 | ||
466 | if (pic->type == PICTURE_TYPE_IDR) | |
467 | pkt->flags |= AV_PKT_FLAG_KEY; | |
468 | ||
469 | pkt->pts = pic->pts; | |
470 | ||
471 | vas = vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer); | |
472 | if (vas != VA_STATUS_SUCCESS) { | |
473 | av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: " | |
474 | "%d (%s).\n", vas, vaErrorStr(vas)); | |
475 | err = AVERROR(EIO); | |
476 | goto fail; | |
477 | } | |
478 | ||
8a62d2c2 | 479 | av_buffer_unref(&pic->output_buffer_ref); |
104c804b MT |
480 | pic->output_buffer = VA_INVALID_ID; |
481 | ||
482 | av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n", | |
483 | pic->display_order, pic->encode_order); | |
484 | return 0; | |
485 | ||
8a62d2c2 MT |
486 | fail_mapped: |
487 | vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer); | |
104c804b | 488 | fail: |
8a62d2c2 MT |
489 | av_buffer_unref(&pic->output_buffer_ref); |
490 | pic->output_buffer = VA_INVALID_ID; | |
104c804b MT |
491 | return err; |
492 | } | |
493 | ||
494 | static int vaapi_encode_discard(AVCodecContext *avctx, | |
495 | VAAPIEncodePicture *pic) | |
496 | { | |
104c804b MT |
497 | vaapi_encode_wait(avctx, pic); |
498 | ||
8a62d2c2 | 499 | if (pic->output_buffer_ref) { |
104c804b MT |
500 | av_log(avctx, AV_LOG_DEBUG, "Discard output for pic " |
501 | "%"PRId64"/%"PRId64".\n", | |
502 | pic->display_order, pic->encode_order); | |
503 | ||
8a62d2c2 | 504 | av_buffer_unref(&pic->output_buffer_ref); |
104c804b MT |
505 | pic->output_buffer = VA_INVALID_ID; |
506 | } | |
507 | ||
508 | return 0; | |
509 | } | |
510 | ||
511 | static VAAPIEncodePicture *vaapi_encode_alloc(void) | |
512 | { | |
513 | VAAPIEncodePicture *pic; | |
514 | ||
515 | pic = av_mallocz(sizeof(*pic)); | |
516 | if (!pic) | |
517 | return NULL; | |
518 | ||
519 | pic->input_surface = VA_INVALID_ID; | |
520 | pic->recon_surface = VA_INVALID_ID; | |
521 | pic->output_buffer = VA_INVALID_ID; | |
522 | ||
523 | return pic; | |
524 | } | |
525 | ||
526 | static int vaapi_encode_free(AVCodecContext *avctx, | |
527 | VAAPIEncodePicture *pic) | |
528 | { | |
529 | int i; | |
530 | ||
531 | if (pic->encode_issued) | |
532 | vaapi_encode_discard(avctx, pic); | |
533 | ||
534 | for (i = 0; i < pic->nb_slices; i++) { | |
535 | av_freep(&pic->slices[i]->priv_data); | |
536 | av_freep(&pic->slices[i]->codec_slice_params); | |
537 | av_freep(&pic->slices[i]); | |
538 | } | |
539 | av_freep(&pic->codec_picture_params); | |
540 | ||
541 | av_frame_free(&pic->input_image); | |
542 | av_frame_free(&pic->recon_image); | |
543 | ||
544 | // Output buffer should already be destroyed. | |
545 | av_assert0(pic->output_buffer == VA_INVALID_ID); | |
546 | ||
547 | av_freep(&pic->priv_data); | |
548 | av_freep(&pic->codec_picture_params); | |
549 | ||
550 | av_free(pic); | |
551 | ||
552 | return 0; | |
553 | } | |
554 | ||
555 | static int vaapi_encode_step(AVCodecContext *avctx, | |
556 | VAAPIEncodePicture *target) | |
557 | { | |
558 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
559 | VAAPIEncodePicture *pic; | |
560 | int i, err; | |
561 | ||
562 | if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING || | |
563 | ctx->issue_mode == ISSUE_MODE_MINIMISE_LATENCY) { | |
564 | // These two modes are equivalent, except that we wait for | |
565 | // immediate completion on each operation if serialised. | |
566 | ||
567 | if (!target) { | |
568 | // No target, nothing to do yet. | |
569 | return 0; | |
570 | } | |
571 | ||
572 | if (target->encode_complete) { | |
573 | // Already done. | |
574 | return 0; | |
575 | } | |
576 | ||
577 | pic = target; | |
578 | for (i = 0; i < pic->nb_refs; i++) { | |
579 | if (!pic->refs[i]->encode_complete) { | |
580 | err = vaapi_encode_step(avctx, pic->refs[i]); | |
581 | if (err < 0) | |
582 | return err; | |
583 | } | |
584 | } | |
585 | ||
586 | err = vaapi_encode_issue(avctx, pic); | |
587 | if (err < 0) | |
588 | return err; | |
589 | ||
590 | } else if (ctx->issue_mode == ISSUE_MODE_MAXIMISE_THROUGHPUT) { | |
591 | int activity; | |
592 | ||
593 | do { | |
594 | activity = 0; | |
595 | for (pic = ctx->pic_start; pic; pic = pic->next) { | |
596 | if (!pic->input_available || pic->encode_issued) | |
597 | continue; | |
598 | for (i = 0; i < pic->nb_refs; i++) { | |
599 | if (!pic->refs[i]->encode_issued) | |
600 | break; | |
601 | } | |
602 | if (i < pic->nb_refs) | |
603 | continue; | |
604 | err = vaapi_encode_issue(avctx, pic); | |
605 | if (err < 0) | |
606 | return err; | |
607 | activity = 1; | |
608 | } | |
609 | } while(activity); | |
610 | ||
611 | if (target) { | |
612 | av_assert0(target->encode_issued && "broken dependencies?"); | |
613 | } | |
614 | ||
615 | } else { | |
616 | av_assert0(0); | |
617 | } | |
618 | ||
619 | return 0; | |
620 | } | |
621 | ||
622 | static int vaapi_encode_get_next(AVCodecContext *avctx, | |
623 | VAAPIEncodePicture **pic_out) | |
624 | { | |
625 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
626 | VAAPIEncodePicture *start, *end, *pic; | |
627 | int i; | |
628 | ||
629 | for (pic = ctx->pic_start; pic; pic = pic->next) { | |
630 | if (pic->next) | |
631 | av_assert0(pic->display_order + 1 == pic->next->display_order); | |
632 | if (pic->display_order == ctx->input_order) { | |
633 | *pic_out = pic; | |
634 | return 0; | |
635 | } | |
636 | } | |
637 | ||
638 | if (ctx->input_order == 0) { | |
639 | // First frame is always an IDR frame. | |
640 | av_assert0(!ctx->pic_start && !ctx->pic_end); | |
641 | ||
642 | pic = vaapi_encode_alloc(); | |
643 | if (!pic) | |
644 | return AVERROR(ENOMEM); | |
645 | ||
646 | pic->type = PICTURE_TYPE_IDR; | |
647 | pic->display_order = 0; | |
648 | pic->encode_order = 0; | |
649 | ||
650 | ctx->pic_start = ctx->pic_end = pic; | |
651 | ||
652 | *pic_out = pic; | |
653 | return 0; | |
654 | } | |
655 | ||
656 | pic = vaapi_encode_alloc(); | |
657 | if (!pic) | |
658 | return AVERROR(ENOMEM); | |
659 | ||
660 | if (ctx->p_per_i == 0 || ctx->p_counter == ctx->p_per_i) { | |
661 | if (ctx->i_per_idr == 0 || ctx->i_counter == ctx->i_per_idr) { | |
662 | pic->type = PICTURE_TYPE_IDR; | |
663 | ctx->i_counter = 0; | |
664 | } else { | |
665 | pic->type = PICTURE_TYPE_I; | |
666 | ++ctx->i_counter; | |
667 | } | |
668 | ctx->p_counter = 0; | |
669 | } else { | |
670 | pic->type = PICTURE_TYPE_P; | |
671 | pic->refs[0] = ctx->pic_end; | |
672 | pic->nb_refs = 1; | |
673 | ++ctx->p_counter; | |
674 | } | |
675 | start = end = pic; | |
676 | ||
677 | if (pic->type != PICTURE_TYPE_IDR) { | |
41ed7ab4 | 678 | // If that was not an IDR frame, add B-frames display-before and |
104c804b MT |
679 | // encode-after it. |
680 | ||
681 | for (i = 0; i < ctx->b_per_p; i++) { | |
682 | pic = vaapi_encode_alloc(); | |
683 | if (!pic) | |
684 | goto fail; | |
685 | ||
686 | pic->type = PICTURE_TYPE_B; | |
687 | pic->refs[0] = ctx->pic_end; | |
688 | pic->refs[1] = end; | |
689 | pic->nb_refs = 2; | |
690 | ||
691 | pic->next = start; | |
692 | pic->display_order = ctx->input_order + ctx->b_per_p - i - 1; | |
693 | pic->encode_order = pic->display_order + 1; | |
694 | start = pic; | |
695 | } | |
696 | } | |
697 | ||
698 | for (i = 0, pic = start; pic; i++, pic = pic->next) { | |
699 | pic->display_order = ctx->input_order + i; | |
700 | if (end->type == PICTURE_TYPE_IDR) | |
701 | pic->encode_order = ctx->input_order + i; | |
702 | else if (pic == end) | |
703 | pic->encode_order = ctx->input_order; | |
704 | else | |
705 | pic->encode_order = ctx->input_order + i + 1; | |
706 | } | |
707 | ||
708 | av_assert0(ctx->pic_end); | |
709 | ctx->pic_end->next = start; | |
710 | ctx->pic_end = end; | |
711 | ||
712 | *pic_out = start; | |
713 | ||
714 | av_log(avctx, AV_LOG_DEBUG, "Pictures:"); | |
715 | for (pic = ctx->pic_start; pic; pic = pic->next) { | |
716 | av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")", | |
717 | picture_type_name[pic->type], | |
718 | pic->display_order, pic->encode_order); | |
719 | } | |
720 | av_log(avctx, AV_LOG_DEBUG, "\n"); | |
721 | ||
722 | return 0; | |
723 | ||
724 | fail: | |
725 | while (start) { | |
726 | pic = start->next; | |
727 | vaapi_encode_free(avctx, start); | |
728 | start = pic; | |
729 | } | |
730 | return AVERROR(ENOMEM); | |
731 | } | |
732 | ||
733 | static int vaapi_encode_mangle_end(AVCodecContext *avctx) | |
734 | { | |
735 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
736 | VAAPIEncodePicture *pic, *last_pic, *next; | |
737 | ||
738 | // Find the last picture we actually have input for. | |
739 | for (pic = ctx->pic_start; pic; pic = pic->next) { | |
740 | if (!pic->input_available) | |
741 | break; | |
742 | last_pic = pic; | |
743 | } | |
744 | ||
745 | if (pic) { | |
746 | av_assert0(last_pic); | |
747 | ||
748 | if (last_pic->type == PICTURE_TYPE_B) { | |
749 | // Some fixing up is required. Change the type of this | |
41ed7ab4 | 750 | // picture to P, then modify preceding B references which |
104c804b MT |
751 | // point beyond it to point at it instead. |
752 | ||
753 | last_pic->type = PICTURE_TYPE_P; | |
754 | last_pic->encode_order = last_pic->refs[1]->encode_order; | |
755 | ||
756 | for (pic = ctx->pic_start; pic != last_pic; pic = pic->next) { | |
757 | if (pic->type == PICTURE_TYPE_B && | |
758 | pic->refs[1] == last_pic->refs[1]) | |
759 | pic->refs[1] = last_pic; | |
760 | } | |
761 | ||
762 | last_pic->nb_refs = 1; | |
763 | last_pic->refs[1] = NULL; | |
764 | } else { | |
765 | // We can use the current structure (no references point | |
766 | // beyond the end), but there are unused pics to discard. | |
767 | } | |
768 | ||
769 | // Discard all following pics, they will never be used. | |
770 | for (pic = last_pic->next; pic; pic = next) { | |
771 | next = pic->next; | |
772 | vaapi_encode_free(avctx, pic); | |
773 | } | |
774 | ||
775 | last_pic->next = NULL; | |
776 | ctx->pic_end = last_pic; | |
777 | ||
778 | } else { | |
779 | // Input is available for all pictures, so we don't need to | |
780 | // mangle anything. | |
781 | } | |
782 | ||
783 | av_log(avctx, AV_LOG_DEBUG, "Pictures at end of stream:"); | |
784 | for (pic = ctx->pic_start; pic; pic = pic->next) { | |
785 | av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")", | |
786 | picture_type_name[pic->type], | |
787 | pic->display_order, pic->encode_order); | |
788 | } | |
789 | av_log(avctx, AV_LOG_DEBUG, "\n"); | |
790 | ||
791 | return 0; | |
792 | } | |
793 | ||
794 | static int vaapi_encode_clear_old(AVCodecContext *avctx) | |
795 | { | |
796 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
797 | VAAPIEncodePicture *pic, *old; | |
798 | int i; | |
799 | ||
800 | while (ctx->pic_start != ctx->pic_end) { | |
801 | old = ctx->pic_start; | |
802 | if (old->encode_order > ctx->output_order) | |
803 | break; | |
804 | ||
805 | for (pic = old->next; pic; pic = pic->next) { | |
806 | if (pic->encode_complete) | |
807 | continue; | |
808 | for (i = 0; i < pic->nb_refs; i++) { | |
809 | if (pic->refs[i] == old) { | |
810 | // We still need this picture because it's referred to | |
811 | // directly by a later one, so it and all following | |
812 | // pictures have to stay. | |
813 | return 0; | |
814 | } | |
815 | } | |
816 | } | |
817 | ||
818 | pic = ctx->pic_start; | |
819 | ctx->pic_start = pic->next; | |
820 | vaapi_encode_free(avctx, pic); | |
821 | } | |
822 | ||
823 | return 0; | |
824 | } | |
825 | ||
826 | int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt, | |
827 | const AVFrame *input_image, int *got_packet) | |
828 | { | |
829 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
830 | VAAPIEncodePicture *pic; | |
831 | int err; | |
832 | ||
833 | if (input_image) { | |
834 | av_log(avctx, AV_LOG_DEBUG, "Encode frame: %ux%u (%"PRId64").\n", | |
835 | input_image->width, input_image->height, input_image->pts); | |
836 | ||
837 | err = vaapi_encode_get_next(avctx, &pic); | |
838 | if (err) { | |
839 | av_log(avctx, AV_LOG_ERROR, "Input setup failed: %d.\n", err); | |
840 | return err; | |
841 | } | |
842 | ||
843 | pic->input_image = av_frame_alloc(); | |
844 | if (!pic->input_image) { | |
845 | err = AVERROR(ENOMEM); | |
846 | goto fail; | |
847 | } | |
848 | err = av_frame_ref(pic->input_image, input_image); | |
849 | if (err < 0) | |
850 | goto fail; | |
851 | pic->input_surface = (VASurfaceID)(uintptr_t)input_image->data[3]; | |
852 | pic->pts = input_image->pts; | |
853 | ||
854 | if (ctx->input_order == 0) | |
855 | ctx->first_pts = pic->pts; | |
856 | if (ctx->input_order == ctx->decode_delay) | |
857 | ctx->dts_pts_diff = pic->pts - ctx->first_pts; | |
858 | if (ctx->output_delay > 0) | |
859 | ctx->ts_ring[ctx->input_order % (3 * ctx->output_delay)] = pic->pts; | |
860 | ||
861 | pic->input_available = 1; | |
862 | ||
863 | } else { | |
864 | if (!ctx->end_of_stream) { | |
865 | err = vaapi_encode_mangle_end(avctx); | |
866 | if (err < 0) | |
867 | goto fail; | |
868 | ctx->end_of_stream = 1; | |
869 | } | |
870 | } | |
871 | ||
872 | ++ctx->input_order; | |
873 | ++ctx->output_order; | |
874 | av_assert0(ctx->output_order + ctx->output_delay + 1 == ctx->input_order); | |
875 | ||
876 | for (pic = ctx->pic_start; pic; pic = pic->next) | |
877 | if (pic->encode_order == ctx->output_order) | |
878 | break; | |
879 | ||
880 | // pic can be null here if we don't have a specific target in this | |
881 | // iteration. We might still issue encodes if things can be overlapped, | |
882 | // even though we don't intend to output anything. | |
883 | ||
884 | err = vaapi_encode_step(avctx, pic); | |
885 | if (err < 0) { | |
886 | av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); | |
887 | goto fail; | |
888 | } | |
889 | ||
890 | if (!pic) { | |
891 | *got_packet = 0; | |
892 | } else { | |
893 | err = vaapi_encode_output(avctx, pic, pkt); | |
894 | if (err < 0) { | |
895 | av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err); | |
896 | goto fail; | |
897 | } | |
898 | ||
899 | if (ctx->output_delay == 0) { | |
900 | pkt->dts = pkt->pts; | |
901 | } else if (ctx->output_order < ctx->decode_delay) { | |
902 | if (ctx->ts_ring[ctx->output_order] < INT64_MIN + ctx->dts_pts_diff) | |
903 | pkt->dts = INT64_MIN; | |
904 | else | |
905 | pkt->dts = ctx->ts_ring[ctx->output_order] - ctx->dts_pts_diff; | |
906 | } else { | |
907 | pkt->dts = ctx->ts_ring[(ctx->output_order - ctx->decode_delay) % | |
908 | (3 * ctx->output_delay)]; | |
909 | } | |
910 | ||
911 | *got_packet = 1; | |
912 | } | |
913 | ||
914 | err = vaapi_encode_clear_old(avctx); | |
915 | if (err < 0) { | |
916 | av_log(avctx, AV_LOG_ERROR, "List clearing failed: %d.\n", err); | |
917 | goto fail; | |
918 | } | |
919 | ||
920 | return 0; | |
921 | ||
922 | fail: | |
923 | // Unclear what to clean up on failure. There are probably some things we | |
924 | // could do usefully clean up here, but for now just leave them for uninit() | |
925 | // to do instead. | |
926 | return err; | |
927 | } | |
928 | ||
80a5d051 | 929 | static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) |
2bfa067d MT |
930 | { |
931 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
932 | VAStatus vas; | |
933 | int i, n, err; | |
934 | VAProfile *profiles = NULL; | |
935 | VAEntrypoint *entrypoints = NULL; | |
936 | VAConfigAttrib attr[] = { | |
892bbbcd MT |
937 | { VAConfigAttribRTFormat }, |
938 | { VAConfigAttribRateControl }, | |
939 | { VAConfigAttribEncMaxRefFrames }, | |
940 | { VAConfigAttribEncPackedHeaders }, | |
2bfa067d MT |
941 | }; |
942 | ||
943 | n = vaMaxNumProfiles(ctx->hwctx->display); | |
944 | profiles = av_malloc_array(n, sizeof(VAProfile)); | |
945 | if (!profiles) { | |
946 | err = AVERROR(ENOMEM); | |
947 | goto fail; | |
948 | } | |
949 | vas = vaQueryConfigProfiles(ctx->hwctx->display, profiles, &n); | |
950 | if (vas != VA_STATUS_SUCCESS) { | |
951 | av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n", | |
952 | vas, vaErrorStr(vas)); | |
953 | err = AVERROR(ENOSYS); | |
954 | goto fail; | |
955 | } | |
956 | for (i = 0; i < n; i++) { | |
957 | if (profiles[i] == ctx->va_profile) | |
958 | break; | |
959 | } | |
960 | if (i >= n) { | |
961 | av_log(ctx, AV_LOG_ERROR, "Encoding profile not found (%d).\n", | |
962 | ctx->va_profile); | |
963 | err = AVERROR(ENOSYS); | |
964 | goto fail; | |
965 | } | |
966 | ||
967 | n = vaMaxNumEntrypoints(ctx->hwctx->display); | |
968 | entrypoints = av_malloc_array(n, sizeof(VAEntrypoint)); | |
969 | if (!entrypoints) { | |
970 | err = AVERROR(ENOMEM); | |
971 | goto fail; | |
972 | } | |
973 | vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile, | |
974 | entrypoints, &n); | |
975 | if (vas != VA_STATUS_SUCCESS) { | |
976 | av_log(ctx, AV_LOG_ERROR, "Failed to query entrypoints for " | |
977 | "profile %u: %d (%s).\n", ctx->va_profile, | |
978 | vas, vaErrorStr(vas)); | |
979 | err = AVERROR(ENOSYS); | |
980 | goto fail; | |
981 | } | |
982 | for (i = 0; i < n; i++) { | |
983 | if (entrypoints[i] == ctx->va_entrypoint) | |
984 | break; | |
985 | } | |
986 | if (i >= n) { | |
987 | av_log(ctx, AV_LOG_ERROR, "Encoding entrypoint not found " | |
988 | "(%d / %d).\n", ctx->va_profile, ctx->va_entrypoint); | |
989 | err = AVERROR(ENOSYS); | |
990 | goto fail; | |
991 | } | |
992 | ||
993 | vas = vaGetConfigAttributes(ctx->hwctx->display, | |
994 | ctx->va_profile, ctx->va_entrypoint, | |
995 | attr, FF_ARRAY_ELEMS(attr)); | |
996 | if (vas != VA_STATUS_SUCCESS) { | |
997 | av_log(avctx, AV_LOG_ERROR, "Failed to fetch config " | |
998 | "attributes: %d (%s).\n", vas, vaErrorStr(vas)); | |
999 | return AVERROR(EINVAL); | |
1000 | } | |
1001 | ||
1002 | for (i = 0; i < FF_ARRAY_ELEMS(attr); i++) { | |
1003 | if (attr[i].value == VA_ATTRIB_NOT_SUPPORTED) { | |
1004 | // Unfortunately we have to treat this as "don't know" and hope | |
1005 | // for the best, because the Intel MJPEG encoder returns this | |
1006 | // for all the interesting attributes. | |
1007 | continue; | |
1008 | } | |
1009 | switch (attr[i].type) { | |
80a5d051 MT |
1010 | case VAConfigAttribRTFormat: |
1011 | if (!(ctx->va_rt_format & attr[i].value)) { | |
1012 | av_log(avctx, AV_LOG_ERROR, "Surface RT format %#x " | |
1013 | "is not supported (mask %#x).\n", | |
1014 | ctx->va_rt_format, attr[i].value); | |
1015 | err = AVERROR(EINVAL); | |
1016 | goto fail; | |
1017 | } | |
1018 | ctx->config_attributes[ctx->nb_config_attributes++] = | |
1019 | (VAConfigAttrib) { | |
1020 | .type = VAConfigAttribRTFormat, | |
1021 | .value = ctx->va_rt_format, | |
1022 | }; | |
1023 | break; | |
2bfa067d MT |
1024 | case VAConfigAttribRateControl: |
1025 | if (!(ctx->va_rc_mode & attr[i].value)) { | |
80a5d051 MT |
1026 | av_log(avctx, AV_LOG_ERROR, "Rate control mode %#x " |
1027 | "is not supported (mask: %#x).\n", | |
1028 | ctx->va_rc_mode, attr[i].value); | |
2bfa067d MT |
1029 | err = AVERROR(EINVAL); |
1030 | goto fail; | |
1031 | } | |
80a5d051 MT |
1032 | ctx->config_attributes[ctx->nb_config_attributes++] = |
1033 | (VAConfigAttrib) { | |
1034 | .type = VAConfigAttribRateControl, | |
1035 | .value = ctx->va_rc_mode, | |
1036 | }; | |
2bfa067d MT |
1037 | break; |
1038 | case VAConfigAttribEncMaxRefFrames: | |
1039 | { | |
1040 | unsigned int ref_l0 = attr[i].value & 0xffff; | |
1041 | unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff; | |
1042 | ||
1043 | if (avctx->gop_size > 1 && ref_l0 < 1) { | |
1044 | av_log(avctx, AV_LOG_ERROR, "P frames are not " | |
80a5d051 | 1045 | "supported (%#x).\n", attr[i].value); |
2bfa067d MT |
1046 | err = AVERROR(EINVAL); |
1047 | goto fail; | |
1048 | } | |
1049 | if (avctx->max_b_frames > 0 && ref_l1 < 1) { | |
1050 | av_log(avctx, AV_LOG_ERROR, "B frames are not " | |
80a5d051 | 1051 | "supported (%#x).\n", attr[i].value); |
2bfa067d MT |
1052 | err = AVERROR(EINVAL); |
1053 | goto fail; | |
1054 | } | |
1055 | } | |
1056 | break; | |
892bbbcd MT |
1057 | case VAConfigAttribEncPackedHeaders: |
1058 | if (ctx->va_packed_headers & ~attr[i].value) { | |
1059 | // This isn't fatal, but packed headers are always | |
1060 | // preferable because they are under our control. | |
1061 | // When absent, the driver is generating them and some | |
1062 | // features may not work (e.g. VUI or SEI in H.264). | |
1063 | av_log(avctx, AV_LOG_WARNING, "Warning: some packed " | |
1064 | "headers are not supported (want %#x, got %#x).\n", | |
1065 | ctx->va_packed_headers, attr[i].value); | |
1066 | ctx->va_packed_headers &= attr[i].value; | |
1067 | } | |
1068 | ctx->config_attributes[ctx->nb_config_attributes++] = | |
1069 | (VAConfigAttrib) { | |
1070 | .type = VAConfigAttribEncPackedHeaders, | |
1071 | .value = ctx->va_packed_headers, | |
1072 | }; | |
1073 | break; | |
80a5d051 MT |
1074 | default: |
1075 | av_assert0(0 && "Unexpected config attribute."); | |
2bfa067d MT |
1076 | } |
1077 | } | |
1078 | ||
1079 | err = 0; | |
1080 | fail: | |
1081 | av_freep(&profiles); | |
1082 | av_freep(&entrypoints); | |
1083 | return err; | |
1084 | } | |
1085 | ||
80a5d051 MT |
1086 | static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) |
1087 | { | |
1088 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
1089 | int hrd_buffer_size; | |
1090 | int hrd_initial_buffer_fullness; | |
1091 | ||
1092 | if (avctx->rc_buffer_size) | |
1093 | hrd_buffer_size = avctx->rc_buffer_size; | |
1094 | else | |
1095 | hrd_buffer_size = avctx->bit_rate; | |
1096 | if (avctx->rc_initial_buffer_occupancy) | |
1097 | hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; | |
1098 | else | |
1099 | hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; | |
1100 | ||
1101 | ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl; | |
1102 | ctx->rc_params.rc = (VAEncMiscParameterRateControl) { | |
1103 | .bits_per_second = avctx->bit_rate, | |
1104 | .target_percentage = 66, | |
1105 | .window_size = 1000, | |
1106 | .initial_qp = (avctx->qmax >= 0 ? avctx->qmax : 40), | |
1107 | .min_qp = (avctx->qmin >= 0 ? avctx->qmin : 18), | |
1108 | .basic_unit_size = 0, | |
1109 | }; | |
1110 | ctx->global_params[ctx->nb_global_params] = | |
1111 | &ctx->rc_params.misc; | |
1112 | ctx->global_params_size[ctx->nb_global_params++] = | |
1113 | sizeof(ctx->rc_params); | |
1114 | ||
1115 | ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD; | |
1116 | ctx->hrd_params.hrd = (VAEncMiscParameterHRD) { | |
1117 | .initial_buffer_fullness = hrd_initial_buffer_fullness, | |
1118 | .buffer_size = hrd_buffer_size, | |
1119 | }; | |
1120 | ctx->global_params[ctx->nb_global_params] = | |
1121 | &ctx->hrd_params.misc; | |
1122 | ctx->global_params_size[ctx->nb_global_params++] = | |
1123 | sizeof(ctx->hrd_params); | |
1124 | ||
1125 | return 0; | |
1126 | } | |
1127 | ||
8a62d2c2 MT |
1128 | static void vaapi_encode_free_output_buffer(void *opaque, |
1129 | uint8_t *data) | |
1130 | { | |
1131 | AVCodecContext *avctx = opaque; | |
1132 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
1133 | VABufferID buffer_id; | |
1134 | ||
1135 | buffer_id = (VABufferID)(uintptr_t)data; | |
1136 | ||
1137 | vaDestroyBuffer(ctx->hwctx->display, buffer_id); | |
1138 | ||
1139 | av_log(avctx, AV_LOG_DEBUG, "Freed output buffer %#x\n", buffer_id); | |
1140 | } | |
1141 | ||
1142 | static AVBufferRef *vaapi_encode_alloc_output_buffer(void *opaque, | |
1143 | int size) | |
1144 | { | |
1145 | AVCodecContext *avctx = opaque; | |
1146 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
1147 | VABufferID buffer_id; | |
1148 | VAStatus vas; | |
1149 | AVBufferRef *ref; | |
1150 | ||
1151 | // The output buffer size is fixed, so it needs to be large enough | |
1152 | // to hold the largest possible compressed frame. We assume here | |
1153 | // that the uncompressed frame plus some header data is an upper | |
1154 | // bound on that. | |
1155 | vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, | |
1156 | VAEncCodedBufferType, | |
80a5d051 | 1157 | 3 * ctx->surface_width * ctx->surface_height + |
8a62d2c2 MT |
1158 | (1 << 16), 1, 0, &buffer_id); |
1159 | if (vas != VA_STATUS_SUCCESS) { | |
1160 | av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream " | |
1161 | "output buffer: %d (%s).\n", vas, vaErrorStr(vas)); | |
1162 | return NULL; | |
1163 | } | |
1164 | ||
1165 | av_log(avctx, AV_LOG_DEBUG, "Allocated output buffer %#x\n", buffer_id); | |
1166 | ||
1167 | ref = av_buffer_create((uint8_t*)(uintptr_t)buffer_id, | |
1168 | sizeof(buffer_id), | |
1169 | &vaapi_encode_free_output_buffer, | |
1170 | avctx, AV_BUFFER_FLAG_READONLY); | |
1171 | if (!ref) { | |
1172 | vaDestroyBuffer(ctx->hwctx->display, buffer_id); | |
1173 | return NULL; | |
1174 | } | |
1175 | ||
1176 | return ref; | |
1177 | } | |
1178 | ||
80a5d051 | 1179 | static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx) |
104c804b MT |
1180 | { |
1181 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
104c804b MT |
1182 | AVVAAPIHWConfig *hwconfig = NULL; |
1183 | AVHWFramesConstraints *constraints = NULL; | |
1184 | enum AVPixelFormat recon_format; | |
104c804b MT |
1185 | int err, i; |
1186 | ||
104c804b MT |
1187 | hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); |
1188 | if (!hwconfig) { | |
1189 | err = AVERROR(ENOMEM); | |
1190 | goto fail; | |
1191 | } | |
1192 | hwconfig->config_id = ctx->va_config; | |
1193 | ||
1194 | constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, | |
1195 | hwconfig); | |
1196 | if (!constraints) { | |
1197 | err = AVERROR(ENOMEM); | |
1198 | goto fail; | |
1199 | } | |
1200 | ||
1201 | // Probably we can use the input surface format as the surface format | |
1202 | // of the reconstructed frames. If not, we just pick the first (only?) | |
1203 | // format in the valid list and hope that it all works. | |
1204 | recon_format = AV_PIX_FMT_NONE; | |
1205 | if (constraints->valid_sw_formats) { | |
1206 | for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { | |
1207 | if (ctx->input_frames->sw_format == | |
1208 | constraints->valid_sw_formats[i]) { | |
1209 | recon_format = ctx->input_frames->sw_format; | |
1210 | break; | |
1211 | } | |
1212 | } | |
11b80303 MT |
1213 | if (recon_format == AV_PIX_FMT_NONE) { |
1214 | // No match. Just use the first in the supported list and | |
1215 | // hope for the best. | |
1216 | recon_format = constraints->valid_sw_formats[0]; | |
1217 | } | |
104c804b MT |
1218 | } else { |
1219 | // No idea what to use; copy input format. | |
1220 | recon_format = ctx->input_frames->sw_format; | |
1221 | } | |
1222 | av_log(avctx, AV_LOG_DEBUG, "Using %s as format of " | |
1223 | "reconstructed frames.\n", av_get_pix_fmt_name(recon_format)); | |
1224 | ||
80a5d051 MT |
1225 | if (ctx->surface_width < constraints->min_width || |
1226 | ctx->surface_height < constraints->min_height || | |
1227 | ctx->surface_width > constraints->max_width || | |
1228 | ctx->surface_height > constraints->max_height) { | |
104c804b MT |
1229 | av_log(avctx, AV_LOG_ERROR, "Hardware does not support encoding at " |
1230 | "size %dx%d (constraints: width %d-%d height %d-%d).\n", | |
80a5d051 | 1231 | ctx->surface_width, ctx->surface_height, |
104c804b MT |
1232 | constraints->min_width, constraints->max_width, |
1233 | constraints->min_height, constraints->max_height); | |
1234 | err = AVERROR(EINVAL); | |
1235 | goto fail; | |
1236 | } | |
1237 | ||
1238 | av_freep(&hwconfig); | |
1239 | av_hwframe_constraints_free(&constraints); | |
1240 | ||
1241 | ctx->recon_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); | |
1242 | if (!ctx->recon_frames_ref) { | |
1243 | err = AVERROR(ENOMEM); | |
1244 | goto fail; | |
1245 | } | |
1246 | ctx->recon_frames = (AVHWFramesContext*)ctx->recon_frames_ref->data; | |
1247 | ||
1248 | ctx->recon_frames->format = AV_PIX_FMT_VAAPI; | |
1249 | ctx->recon_frames->sw_format = recon_format; | |
80a5d051 MT |
1250 | ctx->recon_frames->width = ctx->surface_width; |
1251 | ctx->recon_frames->height = ctx->surface_height; | |
1252 | ctx->recon_frames->initial_pool_size = | |
1253 | avctx->max_b_frames + 3; | |
104c804b MT |
1254 | |
1255 | err = av_hwframe_ctx_init(ctx->recon_frames_ref); | |
1256 | if (err < 0) { | |
1257 | av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed " | |
1258 | "frame context: %d.\n", err); | |
1259 | goto fail; | |
1260 | } | |
104c804b | 1261 | |
80a5d051 MT |
1262 | err = 0; |
1263 | fail: | |
1264 | av_freep(&hwconfig); | |
1265 | av_hwframe_constraints_free(&constraints); | |
1266 | return err; | |
1267 | } | |
1268 | ||
1269 | av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) | |
1270 | { | |
1271 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
1272 | AVVAAPIFramesContext *recon_hwctx = NULL; | |
1273 | VAStatus vas; | |
1274 | int err; | |
1275 | ||
1276 | if (!avctx->hw_frames_ctx) { | |
1277 | av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " | |
1278 | "required to associate the encoding device.\n"); | |
1279 | return AVERROR(EINVAL); | |
1280 | } | |
1281 | ||
1282 | ctx->codec_options = ctx->codec_options_data; | |
1283 | ||
1284 | ctx->va_config = VA_INVALID_ID; | |
1285 | ctx->va_context = VA_INVALID_ID; | |
1286 | ||
1287 | ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); | |
1288 | if (!ctx->priv_data) { | |
1289 | err = AVERROR(ENOMEM); | |
1290 | goto fail; | |
1291 | } | |
1292 | ||
1293 | ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); | |
1294 | if (!ctx->input_frames_ref) { | |
1295 | err = AVERROR(ENOMEM); | |
1296 | goto fail; | |
1297 | } | |
1298 | ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; | |
1299 | ||
1300 | ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); | |
1301 | if (!ctx->device_ref) { | |
1302 | err = AVERROR(ENOMEM); | |
1303 | goto fail; | |
1304 | } | |
1305 | ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; | |
1306 | ctx->hwctx = ctx->device->hwctx; | |
1307 | ||
1308 | err = vaapi_encode_config_attributes(avctx); | |
1309 | if (err < 0) | |
1310 | goto fail; | |
1311 | ||
1312 | vas = vaCreateConfig(ctx->hwctx->display, | |
1313 | ctx->va_profile, ctx->va_entrypoint, | |
1314 | ctx->config_attributes, ctx->nb_config_attributes, | |
1315 | &ctx->va_config); | |
1316 | if (vas != VA_STATUS_SUCCESS) { | |
1317 | av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline " | |
1318 | "configuration: %d (%s).\n", vas, vaErrorStr(vas)); | |
1319 | err = AVERROR(EIO); | |
1320 | goto fail; | |
1321 | } | |
1322 | ||
1323 | err = vaapi_encode_create_recon_frames(avctx); | |
1324 | if (err < 0) | |
1325 | goto fail; | |
1326 | ||
1327 | recon_hwctx = ctx->recon_frames->hwctx; | |
104c804b | 1328 | vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, |
80a5d051 | 1329 | ctx->surface_width, ctx->surface_height, |
104c804b MT |
1330 | VA_PROGRESSIVE, |
1331 | recon_hwctx->surface_ids, | |
1332 | recon_hwctx->nb_surfaces, | |
1333 | &ctx->va_context); | |
1334 | if (vas != VA_STATUS_SUCCESS) { | |
1335 | av_log(avctx, AV_LOG_ERROR, "Failed to create encode pipeline " | |
1336 | "context: %d (%s).\n", vas, vaErrorStr(vas)); | |
1337 | err = AVERROR(EIO); | |
1338 | goto fail; | |
1339 | } | |
1340 | ||
80a5d051 MT |
1341 | ctx->output_buffer_pool = |
1342 | av_buffer_pool_init2(sizeof(VABufferID), avctx, | |
1343 | &vaapi_encode_alloc_output_buffer, NULL); | |
1344 | if (!ctx->output_buffer_pool) { | |
1345 | err = AVERROR(ENOMEM); | |
1346 | goto fail; | |
1347 | } | |
1348 | ||
1349 | if (ctx->va_rc_mode & ~VA_RC_CQP) { | |
1350 | err = vaapi_encode_init_rate_control(avctx); | |
1351 | if (err < 0) | |
1352 | goto fail; | |
1353 | } | |
1354 | ||
1355 | if (ctx->codec->configure) { | |
1356 | err = ctx->codec->configure(avctx); | |
1357 | if (err < 0) | |
1358 | goto fail; | |
1359 | } | |
1360 | ||
104c804b MT |
1361 | ctx->input_order = 0; |
1362 | ctx->output_delay = avctx->max_b_frames; | |
1363 | ctx->decode_delay = 1; | |
1364 | ctx->output_order = - ctx->output_delay - 1; | |
1365 | ||
1366 | if (ctx->codec->sequence_params_size > 0) { | |
1367 | ctx->codec_sequence_params = | |
1368 | av_mallocz(ctx->codec->sequence_params_size); | |
1369 | if (!ctx->codec_sequence_params) { | |
1370 | err = AVERROR(ENOMEM); | |
1371 | goto fail; | |
1372 | } | |
1373 | } | |
1374 | if (ctx->codec->picture_params_size > 0) { | |
1375 | ctx->codec_picture_params = | |
1376 | av_mallocz(ctx->codec->picture_params_size); | |
1377 | if (!ctx->codec_picture_params) { | |
1378 | err = AVERROR(ENOMEM); | |
1379 | goto fail; | |
1380 | } | |
1381 | } | |
1382 | ||
1383 | if (ctx->codec->init_sequence_params) { | |
1384 | err = ctx->codec->init_sequence_params(avctx); | |
1385 | if (err < 0) { | |
1386 | av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation " | |
1387 | "failed: %d.\n", err); | |
1388 | goto fail; | |
1389 | } | |
1390 | } | |
1391 | ||
1392 | // All I are IDR for now. | |
1393 | ctx->i_per_idr = 0; | |
1394 | ctx->p_per_i = ((avctx->gop_size + avctx->max_b_frames) / | |
1395 | (avctx->max_b_frames + 1)); | |
1396 | ctx->b_per_p = avctx->max_b_frames; | |
1397 | ||
1398 | // This should be configurable somehow. (Needs testing on a machine | |
1399 | // where it actually overlaps properly, though.) | |
1400 | ctx->issue_mode = ISSUE_MODE_MAXIMISE_THROUGHPUT; | |
1401 | ||
1402 | return 0; | |
1403 | ||
1404 | fail: | |
104c804b MT |
1405 | ff_vaapi_encode_close(avctx); |
1406 | return err; | |
1407 | } | |
1408 | ||
1409 | av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) | |
1410 | { | |
1411 | VAAPIEncodeContext *ctx = avctx->priv_data; | |
1412 | VAAPIEncodePicture *pic, *next; | |
1413 | ||
1414 | for (pic = ctx->pic_start; pic; pic = next) { | |
1415 | next = pic->next; | |
1416 | vaapi_encode_free(avctx, pic); | |
1417 | } | |
1418 | ||
2bfa067d | 1419 | if (ctx->va_context != VA_INVALID_ID) { |
104c804b | 1420 | vaDestroyContext(ctx->hwctx->display, ctx->va_context); |
2bfa067d MT |
1421 | ctx->va_context = VA_INVALID_ID; |
1422 | } | |
104c804b | 1423 | |
2bfa067d | 1424 | if (ctx->va_config != VA_INVALID_ID) { |
104c804b | 1425 | vaDestroyConfig(ctx->hwctx->display, ctx->va_config); |
2bfa067d MT |
1426 | ctx->va_config = VA_INVALID_ID; |
1427 | } | |
104c804b | 1428 | |
8a62d2c2 MT |
1429 | av_buffer_pool_uninit(&ctx->output_buffer_pool); |
1430 | ||
104c804b MT |
1431 | av_freep(&ctx->codec_sequence_params); |
1432 | av_freep(&ctx->codec_picture_params); | |
1433 | ||
1434 | av_buffer_unref(&ctx->recon_frames_ref); | |
1435 | av_buffer_unref(&ctx->input_frames_ref); | |
1436 | av_buffer_unref(&ctx->device_ref); | |
1437 | ||
1438 | av_freep(&ctx->priv_data); | |
1439 | ||
1440 | return 0; | |
1441 | } |