History

lavc: VAAPI encode common infrastructure

Mark Thompson committed 10 years ago

Commit 104c8041 parent 5d273d34 files · +1316 −0Browse files

Unified · Split

4 files
  1. configure +2 −0
  2. libavcodec/Makefile +1 −0
  3. libavcodec/vaapi_encode.c +1096 −0
  4. libavcodec/vaapi_encode.h +217 −0
configure+2−0
@@ -1708,6 +1708,7 @@ CONFIG_EXTRA=" · 1707 unmodified lines
17081708 texturedsp
17091709 texturedspenc
17101710 tpeldsp
1711+ vaapi_encode
17111712 vc1dsp
17121713 videodsp
17131714 vp3dsp
@@ -1877,6 +1878,7 @@ nvenc_deps_any="dlopen LoadLibrary" · 163 unmodified lines
18771878 nvenc_extralibs='$ldl'
18781879 qsvdec_select="qsv"
18791880 qsvenc_select="qsv"
1881+vaapi_encode_deps="vaapi"
18801882 vc1dsp_select="h264chroma qpeldsp startcode"
18811883
18821884 # decoders / encoders
libavcodec/Makefile+1−0
@@ -107,6 +107,7 @@ OBJS-$(CONFIG_STARTCODE) += startcode.o · 106 unmodified lines
107107 OBJS-$(CONFIG_TEXTUREDSP) += texturedsp.o
108108 OBJS-$(CONFIG_TEXTUREDSPENC) += texturedspenc.o
109109 OBJS-$(CONFIG_TPELDSP) += tpeldsp.o
110+OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o
110111 OBJS-$(CONFIG_VC1DSP) += vc1dsp.o
111112 OBJS-$(CONFIG_VIDEODSP) += videodsp.o
112113 OBJS-$(CONFIG_VP3DSP) += vp3dsp.o
libavcodec/vaapi_encode.c+1096−0
@@ -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, &params, &param_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+}
libavcodec/vaapi_encode.h+217−0
@@ -0,0 +1,217 @@
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+#ifndef AVCODEC_VAAPI_ENCODE_H
20+#define AVCODEC_VAAPI_ENCODE_H
21+
22+#include <stdint.h>
23+
24+#include <va/va.h>
25+
26+#include "libavutil/hwcontext.h"
27+#include "libavutil/hwcontext_vaapi.h"
28+
29+#include "avcodec.h"
30+
31+struct VAAPIEncodeType;
32+struct VAAPIEncodePicture;
33+
34+enum {
35+ MAX_PICTURE_REFERENCES = 2,
36+ MAX_PICTURE_SLICES = 1,
37+ MAX_PARAM_BUFFERS = 16,
38+ MAX_REORDER_DELAY = 16,
39+ MAX_PARAM_BUFFER_SIZE = 1024,
40+ MAX_OUTPUT_BUFFER_SIZE = 1024 * 1024,
41+};
42+
43+enum {
44+ PICTURE_TYPE_IDR = 0,
45+ PICTURE_TYPE_I = 1,
46+ PICTURE_TYPE_P = 2,
47+ PICTURE_TYPE_B = 3,
48+};
49+
50+enum {
51+ // All encode operations are done independently.
52+ ISSUE_MODE_SERIALISE_EVERYTHING = 0,
53+ // Overlap as many operations as possible.
54+ ISSUE_MODE_MAXIMISE_THROUGHPUT,
55+ // Overlap operations only when satisfying parallel dependencies.
56+ ISSUE_MODE_MINIMISE_LATENCY,
57+};
58+
59+typedef struct VAAPIEncodeSlice {
60+ void *priv_data;
61+ void *codec_slice_params;
62+} VAAPIEncodeSlice;
63+
64+typedef struct VAAPIEncodePicture {
65+ struct VAAPIEncodePicture *next;
66+
67+ int64_t display_order;
68+ int64_t encode_order;
69+ int64_t pts;
70+
71+ int type;
72+ int input_available;
73+ int encode_issued;
74+ int encode_complete;
75+
76+ AVFrame *input_image;
77+ VASurfaceID input_surface;
78+
79+ AVFrame *recon_image;
80+ VASurfaceID recon_surface;
81+
82+ int nb_param_buffers;
83+ VABufferID param_buffers[MAX_PARAM_BUFFERS];
84+
85+ VABufferID output_buffer;
86+
87+ void *priv_data;
88+ void *codec_picture_params;
89+
90+ int nb_refs;
91+ struct VAAPIEncodePicture *refs[MAX_PICTURE_REFERENCES];
92+
93+ int nb_slices;
94+ VAAPIEncodeSlice *slices[MAX_PICTURE_SLICES];
95+} VAAPIEncodePicture;
96+
97+typedef struct VAAPIEncodeContext {
98+ const AVClass *class;
99+
100+ // Codec-specific hooks.
101+ const struct VAAPIEncodeType *codec;
102+
103+ // Codec-specific state.
104+ void *priv_data;
105+
106+ VAProfile va_profile;
107+ VAEntrypoint va_entrypoint;
108+ VAConfigID va_config;
109+ VAContextID va_context;
110+
111+ int va_rc_mode;
112+
113+ AVBufferRef *device_ref;
114+ AVHWDeviceContext *device;
115+ AVVAAPIDeviceContext *hwctx;
116+
117+ AVBufferRef *input_frames_ref;
118+ AVHWFramesContext *input_frames;
119+
120+ // Input size, set from input frames.
121+ int input_width;
122+ int input_height;
123+ // Aligned size, set by codec init, becomes hwframe size.
124+ int aligned_width;
125+ int aligned_height;
126+
127+ int nb_recon_frames;
128+ AVBufferRef *recon_frames_ref;
129+ AVHWFramesContext *recon_frames;
130+
131+ VAConfigAttrib *config_attributes;
132+ int nb_config_attributes;
133+
134+ // Per-sequence parameter structure (VAEncSequenceParameterBuffer*).
135+ void *codec_sequence_params;
136+
137+ // Per-sequence parameters found in the per-picture parameter
138+ // structure (VAEncPictureParameterBuffer*).
139+ void *codec_picture_params;
140+
141+ // Current encoding window, in display (input) order.
142+ VAAPIEncodePicture *pic_start, *pic_end;
143+
144+ // Next input order index (display order).
145+ int64_t input_order;
146+ // Number of frames that output is behind input.
147+ int64_t output_delay;
148+ // Number of frames decode output will need to be delayed.
149+ int64_t decode_delay;
150+ // Next output order index (encode order).
151+ int64_t output_order;
152+
153+ int issue_mode;
154+
155+ // Timestamp handling.
156+ int64_t first_pts;
157+ int64_t dts_pts_diff;
158+ int64_t ts_ring[MAX_REORDER_DELAY * 3];
159+
160+ // Frame type decision.
161+ int i_per_idr;
162+ int p_per_i;
163+ int b_per_p;
164+ int idr_counter;
165+ int i_counter;
166+ int p_counter;
167+ int end_of_stream;
168+
169+} VAAPIEncodeContext;
170+
171+
172+typedef struct VAAPIEncodeType {
173+ size_t priv_data_size;
174+
175+ int (*init)(AVCodecContext *avctx);
176+ int (*close)(AVCodecContext *avctx);
177+
178+ size_t sequence_params_size;
179+ size_t picture_params_size;
180+ size_t slice_params_size;
181+
182+ int (*init_sequence_params)(AVCodecContext *avctx);
183+ int (*init_picture_params)(AVCodecContext *avctx,
184+ VAAPIEncodePicture *pic);
185+ int (*init_slice_params)(AVCodecContext *avctx,
186+ VAAPIEncodePicture *pic,
187+ VAAPIEncodeSlice *slice);
188+
189+ int sequence_header_type;
190+ int picture_header_type;
191+ int slice_header_type;
192+
193+ int (*write_sequence_header)(AVCodecContext *avctx,
194+ char *data, size_t *data_len);
195+ int (*write_picture_header)(AVCodecContext *avctx,
196+ VAAPIEncodePicture *pic,
197+ char *data, size_t *data_len);
198+ int (*write_slice_header)(AVCodecContext *avctx,
199+ VAAPIEncodePicture *pic,
200+ VAAPIEncodeSlice *slice,
201+ char *data, size_t *data_len);
202+
203+ int (*write_extra_buffer)(AVCodecContext *avctx,
204+ VAAPIEncodePicture *pic,
205+ int index, int *type,
206+ char *data, size_t *data_len);
207+} VAAPIEncodeType;
208+
209+
210+int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt,
211+ const AVFrame *input_image, int *got_packet);
212+
213+int ff_vaapi_encode_init(AVCodecContext *avctx,
214+ const VAAPIEncodeType *type);
215+int ff_vaapi_encode_close(AVCodecContext *avctx);
216+
217+#endif /* AVCODEC_VAAPI_ENCODE_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t