1 /*
2 * H.266 encoding using the VVenC library
3 *
4 * Copyright (C) 2022, Thomas Siedel
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <vvenc/vvenc.h>
24 #include <vvenc/vvencCfg.h>
25 #include <vvenc/version.h>
26
36
43
44 #define VVENC_VERSION_INT AV_VERSION_INT(VVENC_VERSION_MAJOR, \
45 VVENC_VERSION_MINOR, \
46 VVENC_VERSION_PATCH)
47
62
64 const char *fmt, va_list args)
65 {
66 vvenc_config params;
67 vvencEncoder *encoder =
ctx;
68 if (encoder) {
69 vvenc_config_default(¶ms);
70 vvenc_get_config(encoder, ¶ms);
71 if ((
int)params.m_verbosity >=
level)
72 vfprintf(
level == 1 ? stderr : stdout, fmt, args);
73 }
74 }
75
77 {
79 params->m_verbosity = VVENC_SILENT;
81 params->m_verbosity = VVENC_DETAILS;
83 params->m_verbosity = VVENC_NOTICE;
85 params->m_verbosity = VVENC_WARNING;
86 }
87
89 {
90 params->m_internChromaFormat = VVENC_CHROMA_420;
91 params->m_inputBitDepth[0] = 10;
92 }
93
95 {
99 params->m_matrixCoefficients = (int) avctx->
colorspace;
101 params->m_transferCharacteristics = (int) avctx->
color_trc;
102
105 VVENC_HDR_PQ_BT2020 : VVENC_HDR_PQ;
111 VVENC_HDR_HLG_BT2020 : VVENC_HDR_HLG;
112 }
113
114 if (params->m_HdrMode == VVENC_HDR_OFF &&
116 params->m_vuiParametersPresent = 1;
117 params->m_colourDescriptionPresent = true;
118 }
119 }
120
122 {
126 } else {
129 }
130
132
133 #if FF_API_TICKS_PER_FRAME
135 #endif
136 params->m_TicksPerSecond = -1; /* auto mode for ticks per frame = 1 */
137 #if FF_API_TICKS_PER_FRAME
138 } else {
139 params->m_TicksPerSecond =
142 }
143 #endif
145 }
146
148 {
151 int parse_ret;
153
157 parse_ret = vvenc_set_param(params, en->
key, en->
value);
158 switch (parse_ret) {
159 case VVENC_PARAM_BAD_NAME:
162 break;
163 case VVENC_PARAM_BAD_VALUE:
166 break;
167 default:
168 break;
169 }
170
173 "not available. Use option 'passlogfile'\n");
175 }
178 "not available. Use option 'pass'\n", en->
key);
180 }
181 }
183 }
184
186 {
187 params->m_RCNumPasses = 1;
192 }
193 params->m_RCNumPasses = 2;
195 params->m_RCPass = 1;
196 else
197 params->m_RCPass = 2;
198 }
199
201 #if VVENC_VERSION_INT >= AV_VERSION_INT(1,8,0)
203 #endif
204
205 #if VVENC_VERSION_INT < AV_VERSION_INT(1,11,0)
206 /* rc_max_rate without a bit_rate enables capped CQF mode.
207 (QP + subj. optimization + max. bitrate) */
210 "needs at least vvenc version >= 1.11.0 (current version %s)\n", vvenc_get_version());
212 }
213 #endif
214 }
215 return 0;
216 }
217
219 {
222 ret = vvenc_get_headers(
s->encoder,
s->au);
225 vvenc_get_last_error(
s->encoder));
227 }
228
229 if (
s->au->payloadUsedSize <= 0) {
231 }
232
237 }
238
240 }
241 return 0;
242 }
243
245 {
249 vvenc_config params;
250 vvencPresetMode
preset = (vvencPresetMode)
s->preset;
251
255 }
256
257 vvenc_config_default(¶ms);
258
261 else
263
266
268
271
272 /* GOP settings (IDR/CRA) */
274 params.m_DecodingRefreshType = VVENC_DRT_IDR;
275
277 params.m_GOPSize = 1;
278 params.m_IntraPeriod = 1;
279 } else
280 params.m_IntraPeriodSec =
s->intra_refresh_sec;
281
282 params.m_AccessUnitDelimiter = true;
283 params.m_usePerceptQPA =
s->qpa;
284 params.m_levelTier = (vvencTier)
s->tier;
285
287 params.m_level = (vvencLevel)avctx->
level;
288
290 if (VVENC_PARAM_BAD_VALUE == vvenc_set_param(¶ms,
"level",
s->level)) {
293 }
294 }
295
297
299
301
305
309
310 s->encoder = vvenc_encoder_create();
314 }
315
317 ret = vvenc_encoder_open(
s->encoder, ¶ms);
320 vvenc_get_last_error(
s->encoder));
322 }
323
324 vvenc_get_config(
s->encoder, ¶ms);
/* get the adapted config */
325
328 av_log(avctx,
AV_LOG_INFO,
"%s\n", vvenc_get_config_as_string(¶ms, params.m_verbosity));
329
330 if (params.m_RCNumPasses == 2) {
331 ret = vvenc_init_pass(
s->encoder, params.m_RCPass - 1,
s->stats);
334 vvenc_get_last_error(
s->encoder));
336 }
337 }
338
339 s->au = vvenc_accessUnit_alloc();
343 }
344 vvenc_accessUnit_alloc_payload(
s->au, avctx->
width * avctx->
height);
345 if (!
s->au->payload) {
349 }
350
354
355 s->encode_done =
false;
356 return 0;
357 }
358
360 {
362
364 vvenc_accessUnit_free(
s->au,
true);
365
367 vvenc_print_summary(
s->encoder);
368
369 if (0 != vvenc_encoder_close(
s->encoder))
371 }
372
373 return 0;
374 }
375
377 int *got_packet)
378 {
380 vvencYUVBuffer *pyuvbuf;
381 vvencYUVBuffer yuvbuf;
383
386 vvenc_YUVBuffer_default(&yuvbuf);
387 yuvbuf.planes[0].ptr = (int16_t *)
frame->data[0];
388 yuvbuf.planes[1].ptr = (int16_t *)
frame->data[1];
389 yuvbuf.planes[2].ptr = (int16_t *)
frame->data[2];
390
391 yuvbuf.planes[0].width =
frame->width;
392 yuvbuf.planes[0].height =
frame->height;
393 yuvbuf.planes[0].stride =
frame->linesize[0] >> 1;
/* stride is used in 16bit samples in vvenc */
394
395 yuvbuf.planes[1].width =
frame->width >> 1;
396 yuvbuf.planes[1].height =
frame->height >> 1;
397 yuvbuf.planes[1].stride =
frame->linesize[1] >> 1;
398
399 yuvbuf.planes[2].width =
frame->width >> 1;
400 yuvbuf.planes[2].height =
frame->height >> 1;
401 yuvbuf.planes[2].stride =
frame->linesize[2] >> 1;
402
403 yuvbuf.cts =
frame->pts;
404 yuvbuf.ctsValid = true;
405 pyuvbuf = &yuvbuf;
406 }
407
408 if (!
s->encode_done) {
409 if (vvenc_encode(
s->encoder, pyuvbuf,
s->au, &
s->encode_done) != 0)
411 } else
412 return 0;
413
414 if (
s->au->payloadUsedSize > 0) {
418
419 memcpy(
pkt->
data,
s->au->payload,
s->au->payloadUsedSize);
420
426
427 *got_packet = 1;
428 return 0;
429 }
430
431 return 0;
432 }
433
437 };
438
439 #define OFFSET(x) offsetof(VVenCContext, x)
440 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
443 {
"faster",
"0", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_FASTER}, INT_MIN, INT_MAX,
VE,
"preset" },
444 {
"fast",
"1", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_FAST}, INT_MIN, INT_MAX,
VE,
"preset" },
445 {
"medium",
"2", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_MEDIUM}, INT_MIN, INT_MAX,
VE,
"preset" },
446 {
"slow",
"3", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOW}, INT_MIN, INT_MAX,
VE,
"preset" },
447 {
"slower",
"4", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOWER}, INT_MIN, INT_MAX,
VE,
"preset" },
449 {
"qpa",
"set subjective (perceptually motivated) optimization",
OFFSET(qpa),
AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1,
VE},
452 {
"period",
"set (intra) refresh period in seconds",
OFFSET(intra_refresh_sec),
AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX,
VE },
453 {
"vvenc-params",
"set the vvenc configuration using a :-separated list of key=value parameters",
OFFSET(vvenc_opts),
AV_OPT_TYPE_DICT, { 0 }, 0, 0,
VE },
459 };
460
466 };
467
469 { "b", "0" },
470 { "g", "-1" },
472 };
473
475 .
p.
name =
"libvvenc",
482 .p.priv_class = &class,
483 .p.wrapper_name = "libvvenc",
491 };