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
131 params->m_TicksPerSecond = -1; /* auto mode for ticks per frame = 1 */
132 }
133
135 {
138 int parse_ret;
140
144 parse_ret = vvenc_set_param(params, en->
key, en->
value);
145 switch (parse_ret) {
146 case VVENC_PARAM_BAD_NAME:
149 break;
150 case VVENC_PARAM_BAD_VALUE:
153 break;
154 default:
155 break;
156 }
157
160 "not available. Use option 'passlogfile'\n");
162 }
165 "not available. Use option 'pass'\n", en->
key);
167 }
168 }
170 }
171
173 {
174 params->m_RCNumPasses = 1;
179 }
180 params->m_RCNumPasses = 2;
182 params->m_RCPass = 1;
183 else
184 params->m_RCPass = 2;
185 }
186
188 #if VVENC_VERSION_INT >= AV_VERSION_INT(1,8,0)
190 #endif
191
192 #if VVENC_VERSION_INT < AV_VERSION_INT(1,11,0)
193 /* rc_max_rate without a bit_rate enables capped CQF mode.
194 (QP + subj. optimization + max. bitrate) */
197 "needs at least vvenc version >= 1.11.0 (current version %s)\n", vvenc_get_version());
199 }
200 #endif
201 }
202 return 0;
203 }
204
206 {
209 ret = vvenc_get_headers(
s->encoder,
s->au);
212 vvenc_get_last_error(
s->encoder));
214 }
215
216 if (
s->au->payloadUsedSize <= 0) {
218 }
219
224 }
225
227 }
228 return 0;
229 }
230
232 {
236 vvenc_config params;
237 vvencPresetMode
preset = (vvencPresetMode)
s->preset;
238
242 }
243
244 vvenc_config_default(¶ms);
245
248 else
250
253
255
258
259 /* GOP settings (IDR/CRA) */
261 params.m_DecodingRefreshType = VVENC_DRT_IDR;
262
264 params.m_GOPSize = 1;
265 params.m_IntraPeriod = 1;
266 } else
267 params.m_IntraPeriodSec =
s->intra_refresh_sec;
268
269 params.m_AccessUnitDelimiter = true;
270 params.m_usePerceptQPA =
s->qpa;
271 params.m_levelTier = (vvencTier)
s->tier;
272
274 params.m_level = (vvencLevel)avctx->
level;
275
277 if (VVENC_PARAM_BAD_VALUE == vvenc_set_param(¶ms,
"level",
s->level)) {
280 }
281 }
282
284
286
288
292
296
297 s->encoder = vvenc_encoder_create();
301 }
302
304 ret = vvenc_encoder_open(
s->encoder, ¶ms);
307 vvenc_get_last_error(
s->encoder));
309 }
310
311 vvenc_get_config(
s->encoder, ¶ms);
/* get the adapted config */
312
315 av_log(avctx,
AV_LOG_INFO,
"%s\n", vvenc_get_config_as_string(¶ms, params.m_verbosity));
316
317 if (params.m_RCNumPasses == 2) {
318 ret = vvenc_init_pass(
s->encoder, params.m_RCPass - 1,
s->stats);
321 vvenc_get_last_error(
s->encoder));
323 }
324 }
325
326 s->au = vvenc_accessUnit_alloc();
330 }
331 vvenc_accessUnit_alloc_payload(
s->au, avctx->
width * avctx->
height);
332 if (!
s->au->payload) {
336 }
337
341
342 s->encode_done =
false;
343 return 0;
344 }
345
347 {
349
351 vvenc_accessUnit_free(
s->au,
true);
352
354 vvenc_print_summary(
s->encoder);
355
356 if (0 != vvenc_encoder_close(
s->encoder))
358 }
359
360 return 0;
361 }
362
364 int *got_packet)
365 {
367 vvencYUVBuffer *pyuvbuf;
368 vvencYUVBuffer yuvbuf;
370
373 vvenc_YUVBuffer_default(&yuvbuf);
374 yuvbuf.planes[0].ptr = (int16_t *)
frame->data[0];
375 yuvbuf.planes[1].ptr = (int16_t *)
frame->data[1];
376 yuvbuf.planes[2].ptr = (int16_t *)
frame->data[2];
377
378 yuvbuf.planes[0].width =
frame->width;
379 yuvbuf.planes[0].height =
frame->height;
380 yuvbuf.planes[0].stride =
frame->linesize[0] >> 1;
/* stride is used in 16bit samples in vvenc */
381
382 yuvbuf.planes[1].width =
frame->width >> 1;
383 yuvbuf.planes[1].height =
frame->height >> 1;
384 yuvbuf.planes[1].stride =
frame->linesize[1] >> 1;
385
386 yuvbuf.planes[2].width =
frame->width >> 1;
387 yuvbuf.planes[2].height =
frame->height >> 1;
388 yuvbuf.planes[2].stride =
frame->linesize[2] >> 1;
389
390 yuvbuf.cts =
frame->pts;
391 yuvbuf.ctsValid = true;
392 pyuvbuf = &yuvbuf;
393 }
394
395 if (!
s->encode_done) {
396 if (vvenc_encode(
s->encoder, pyuvbuf,
s->au, &
s->encode_done) != 0)
398 } else
399 return 0;
400
401 if (
s->au->payloadUsedSize > 0) {
405
406 memcpy(
pkt->
data,
s->au->payload,
s->au->payloadUsedSize);
407
413
414 *got_packet = 1;
415 return 0;
416 }
417
418 return 0;
419 }
420
424 };
425
426 #define OFFSET(x) offsetof(VVenCContext, x)
427 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
430 {
"faster",
"0", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_FASTER}, INT_MIN, INT_MAX,
VE,
"preset" },
431 {
"fast",
"1", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_FAST}, INT_MIN, INT_MAX,
VE,
"preset" },
432 {
"medium",
"2", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_MEDIUM}, INT_MIN, INT_MAX,
VE,
"preset" },
433 {
"slow",
"3", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOW}, INT_MIN, INT_MAX,
VE,
"preset" },
434 {
"slower",
"4", 0,
AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOWER}, INT_MIN, INT_MAX,
VE,
"preset" },
436 {
"qpa",
"set subjective (perceptually motivated) optimization",
OFFSET(qpa),
AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1,
VE},
439 {
"period",
"set (intra) refresh period in seconds",
OFFSET(intra_refresh_sec),
AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX,
VE },
440 {
"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 },
446 };
447
453 };
454
456 { "b", "0" },
457 { "g", "-1" },
459 };
460
462 .
p.
name =
"libvvenc",
469 .p.priv_class = &class,
470 .p.wrapper_name = "libvvenc",
478 };