1 /*
2 * libxeve encoder
3 * EVC (MPEG-5 Essential Video Coding) encoding using XEVE MPEG-5 EVC encoder library
4 *
5 * Copyright (C) 2021 Dawid Kozinski <d.kozinski@samsung.com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
25 #include <stdlib.h>
26
27 #include <xeve.h>
28
37
44
45 #define MAX_BS_BUF (16*1024*1024)
46
47 /**
48 * Error codes
49 */
50 #define XEVE_PARAM_BAD_NAME -100
51 #define XEVE_PARAM_BAD_VALUE -200
52
53 /**
54 * Encoder states
55 *
56 * STATE_ENCODING - the encoder receives and processes input frames
57 * STATE_BUMPING - there are no more input frames, however the encoder still processes previously received data
58 */
63
64 /**
65 * The structure stores all the states associated with the instance of Xeve MPEG-5 EVC encoder
66 */
69
70 XEVE
id;
// XEVE instance identifier
71 XEVE_CDSC
cdsc;
// coding parameters i.e profile, width & height of input frame, num of therads, frame rate ...
72 XEVE_BITB
bitb;
// bitstream buffer (output)
73 XEVE_STAT
stat;
// encoding status (output)
74 XEVE_IMGB
imgb;
// image buffer (input)
75
76 State state;
// encoder state (skipping, encoding, bumping)
77
79 int preset_id;
// preset of xeve ( fast, medium, slow, placebo)
80 int tune_id;
// tune of xeve (psnr, zerolatency)
81
82 // variables for rate control modes
83 int rc_mode;
// Rate control mode [ 0(CQP) / 1(ABR) / 2(CRF) ]
84 int qp;
// quantization parameter (QP) [0,51]
85 int crf;
// constant rate factor (CRF) [10,49]
86
87 int hash;
// embed picture signature (HASH) for conformance checking in decoding
88 int sei_info;
// embed Supplemental enhancement information while encoding
89
90 int color_format;
// input data color format: currently only XEVE_CF_YCBCR420 is supported
91
94
95 /**
96 * Convert FFmpeg pixel format (AVPixelFormat) to XEVE pre-defined color format
97 *
98 * @param[in] av_pix_fmt pixel format (@see https://ffmpeg.org/doxygen/trunk/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5)
99 * @param[out] xeve_col_fmt XEVE pre-defined color format (@see xeve.h)
100 *
101 * @return 0 on success, negative value on failure
102 */
104 {
105 switch (av_pix_fmt) {
107 *xeve_col_fmt = XEVE_CF_YCBCR420;
108 break;
110 *xeve_col_fmt = XEVE_CF_YCBCR420;
111 break;
112 default:
113 *xeve_col_fmt = XEVE_CF_UNKNOWN;
115 }
116
117 return 0;
118 }
119
120 /**
121 * Convert FFmpeg pixel format (AVPixelFormat) into XEVE pre-defined color space
122 *
123 * @param[in] px_fmt pixel format (@see https://ffmpeg.org/doxygen/trunk/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5)
124 *
125 * @return XEVE pre-defined color space (@see xeve.h) on success, XEVE_CF_UNKNOWN on failure
126 */
128 {
129 /* color space of input image */
130 int cs = XEVE_CF_UNKNOWN;
131
132 switch (av_pix_fmt) {
134 cs = XEVE_CS_YCBCR420;
135 break;
137 #if AV_HAVE_BIGENDIAN
138 cs = XEVE_CS_SET(XEVE_CF_YCBCR420, 10, 1);
139 #else
140 cs = XEVE_CS_YCBCR420_10LE;
141 #endif
142
143 break;
144 default:
145 cs = XEVE_CF_UNKNOWN;
146 break;
147 }
148
149 return cs;
150 }
151
152 /**
153 * The function returns a pointer to the object of the XEVE_CDSC type.
154 * XEVE_CDSC contains all encoder parameters that should be initialized before the encoder is used.
155 *
156 * The field values of the XEVE_CDSC structure are populated based on:
157 * - the corresponding field values of the AvCodecConetxt structure,
158 * - the xeve encoder specific option values,
159 * (the full list of options available for xeve encoder is displayed after executing the command ./ffmpeg --help encoder = libxeve)
160 *
161 * The order of processing input data and populating the XEVE_CDSC structure
162 * 1) first, the fields of the AVCodecContext structure corresponding to the provided input options are processed,
163 * (i.e -pix_fmt yuv420p -s:v 1920x1080 -r 30 -profile:v 0)
164 * 2) then xeve-specific options added as AVOption to the xeve AVCodec implementation
165 * (i.e -preset 0)
166 *
167 * Keep in mind that, there are options that can be set in different ways.
168 * In this case, please follow the above-mentioned order of processing.
169 * The most recent assignments overwrite the previous values.
170 *
171 * @param[in] avctx codec context (AVCodecContext)
172 * @param[out] cdsc contains all Xeve MPEG-5 EVC encoder encoder parameters that should be initialized before the encoder is use
173 *
174 * @return 0 on success, negative error code on failure
175 */
177 {
180
182
183 /* initialize xeve_param struct with default values */
184 ret = xeve_param_default(&cdsc->param);
185 if (XEVE_FAILED(
ret)) {
188 }
189
190 /* read options from AVCodecContext */
191 if (avctx->
width > 0)
192 cdsc->param.w = avctx->
width;
193
195 cdsc->param.h = avctx->
height;
196
198 // fps can be float number, but xeve API doesn't support it
200 }
201
202 // GOP size (key-frame interval, I-picture period)
203 cdsc->param.keyint = avctx->
gop_size;
// 0: only one I-frame at the first time; 1: every frame is coded in I-frame
204
208 else {
210 "Acceptable values for bf option (maximum number of B frames) are 0,1,3,7 or 15\n", avctx->
max_b_frames);
212 }
213
214 cdsc->param.level_idc = avctx->
level;
215
218
219 cdsc->param.rc_type = xectx->
rc_mode;
220
221 if (xectx->
rc_mode == XEVE_RC_CQP)
222 cdsc->param.qp = xectx->
qp;
223 else if (xectx->
rc_mode == XEVE_RC_ABR) {
225 av_log(avctx,
AV_LOG_ERROR,
"Not supported bitrate bit_rate and rc_max_rate > %d000\n", INT_MAX);
227 }
228 cdsc->param.bitrate = (
int)(avctx->
bit_rate / 1000);
229 }
else if (xectx->
rc_mode == XEVE_RC_CRF)
230 cdsc->param.crf = xectx->
crf;
231 else {
234 }
235
240 cdsc->param.threads = XEVE_MAX_THREADS;
241 else
243
244
246
247 cdsc->param.cs = XEVE_CS_SET(xectx->
color_format, cdsc->param.codec_bit_depth, AV_HAVE_BIGENDIAN);
248
250
252 if (XEVE_FAILED(
ret)) {
255 }
256
257 return 0;
258 }
259
260 /**
261 * Set XEVE_CFG_SET_USE_PIC_SIGNATURE for encoder
262 *
263 * @param[in] logger context
264 * @param[in] id XEVE encodec instance identifier
265 * @param[in] ctx the structure stores all the states associated with the instance of Xeve MPEG-5 EVC encoder
266 *
267 * @return 0 on success, negative error code on failure
268 */
270 {
273
274 // embed SEI messages identifying encoder parameters and command line arguments
275 // - 0: off\n"
276 // - 1: emit sei info"
277 //
278 // SEI - Supplemental enhancement information contains information
279 // that is not necessary to decode the samples of coded pictures from VCL NAL units.
280 // Some SEI message information is required to check bitstream conformance
281 // and for output timing decoder conformance.
282 // @see ISO_IEC_23094-1_2020 7.4.3.5
283 // @see ISO_IEC_23094-1_2020 Annex D
284 ret = xeve_config(
id, XEVE_CFG_SET_SEI_CMD, &
ctx->sei_info, &
size);
// sei_cmd_info
285 if (XEVE_FAILED(
ret)) {
288 }
289
290 ret = xeve_config(
id, XEVE_CFG_SET_USE_PIC_SIGNATURE, &
ctx->hash, &
size);
291 if (XEVE_FAILED(
ret)) {
294 }
295
296 return 0;
297 }
298
299 /**
300 * @brief Switch encoder to bumping mode
301 *
302 * @param id XEVE encodec instance identifier
303 * @return 0 on success, negative error code on failure
304 */
306 {
309 if (XEVE_FAILED(xeve_config(
id, XEVE_CFG_SET_FORCE_OUT, (
void *)(&
val), &
size)))
311
312 return 0;
313 }
314
315 /**
316 * @brief Initialize eXtra-fast Essential Video Encoder codec
317 * Create an encoder instance and allocate all the needed resources
318 *
319 * @param avctx codec context
320 * @return 0 on success, negative error code on failure
321 */
323 {
325 unsigned char *bs_buf =
NULL;
327 int shift_h = 0;
328 int shift_v = 0;
329 int width_chroma = 0;
330 int height_chroma = 0;
331 XEVE_IMGB *imgb =
NULL;
333
334 XEVE_CDSC *cdsc = &(xectx->
cdsc);
335
336 /* allocate bitstream buffer */
338 if (bs_buf ==
NULL) {
341 }
342 xectx->
bitb.addr = bs_buf;
344
345 /* read configurations and set values for created descriptor (XEVE_CDSC) */
349 }
350
351 if ((
ret = xeve_param_check(&cdsc->param)) != 0) {
354 }
355
356 {
359 if ((
ret = xeve_param_parse(&cdsc->param, en->
key, en->
value)) < 0) {
361 "Error parsing option '%s = %s'.\n",
363 }
364 }
365 }
366
367 /* create encoder */
368 xectx->
id = xeve_create(cdsc,
NULL);
372 }
373
377 }
378
382 }
383
384 // Chroma subsampling
385 //
386 // YUV format explanation
387 // shift_h == 1 && shift_v == 1 : YUV420
388 // shift_h == 1 && shift_v == 0 : YUV422
389 // shift_h == 0 && shift_v == 0 : YUV444
390 //
393
394 /* set default values for input image buffer */
397 imgb->np = 3; /* only for yuv420p, yuv420ple */
398
399 for (
i = 0;
i < imgb->np;
i++)
400 imgb->x[
i] = imgb->y[
i] = 0;
401
402 imgb->w[0] = imgb->aw[0] = avctx->
width;
// width luma
403 imgb->w[1] = imgb->w[2] = imgb->aw[1] = imgb->aw[2] = width_chroma;
404 imgb->h[0] = imgb->ah[0] = avctx->
height;
// height luma
405 imgb->h[1] = imgb->h[2] = imgb->ah[1] = imgb->ah[2] = height_chroma;
406
408
409 return 0;
410 }
411
412 /**
413 * Encode raw data frame into EVC packet
414 *
415 * @param[in] avctx codec context
416 * @param[out] avpkt output AVPacket containing encoded data
417 * @param[in] frame AVFrame containing the raw data to be encoded
418 * @param[out] got_packet encoder sets to 0 or 1 to indicate that a
419 * non-empty packet was returned in pkt
420 *
421 * @return 0 on success, negative error code on failure
422 */
425 {
428
429 // No more input frames are available but encoder still can have some data in its internal buffer to process
430 // and some frames to dump.
434 else {
436 return 0;
437 }
438 }
439
442 XEVE_IMGB *imgb =
NULL;
443
445
446 for (
i = 0;
i < imgb->np;
i++) {
449 }
450
452
453 /* push image to encoder */
454 ret = xeve_push(xectx->
id, imgb);
455 if (XEVE_FAILED(
ret)) {
458 }
459 }
461 /* encoding */
462 ret = xeve_encode(xectx->
id, &(xectx->
bitb), &(xectx->
stat));
463 if (XEVE_FAILED(
ret)) {
466 }
467
468 /* store bitstream */
469 if (
ret == XEVE_OK_OUT_NOT_AVAILABLE) {
// Return OK but picture is not available yet
470 *got_packet = 0;
471 return 0;
472 }
else if (
ret == XEVE_OK) {
473 int av_pic_type;
474
475 if (xectx->
stat.write > 0) {
476
480
481 memcpy(avpkt->
data, xectx->
bitb.addr, xectx->
stat.write);
482
485
486 avpkt->
pts = xectx->
bitb.ts[XEVE_TS_PTS];
487 avpkt->
dts = xectx->
bitb.ts[XEVE_TS_DTS];
488
489 switch(xectx->
stat.stype) {
490 case XEVE_ST_I:
493 break;
494 case XEVE_ST_P:
496 break;
497 case XEVE_ST_B:
499 break;
500 case XEVE_ST_UNKNOWN:
503 }
504
506
507 *got_packet = 1;
508 }
509 }
else if (
ret == XEVE_OK_NO_MORE_FRM) {
510 // Return OK but no more frames
511 return 0;
512 } else {
515 }
516 } else {
519 }
520
521 return 0;
522 }
523
524 /**
525 * Destroy the encoder and release all the allocated resources
526 *
527 * @param avctx codec context
528 * @return 0 on success, negative error code on failure
529 */
531 {
533
535 xeve_delete(xectx->
id);
537 }
538
539 av_free(xectx->
bitb.addr);
/* release bitstream buffer */
540
541 return 0;
542 }
543
544 #define OFFSET(x) offsetof(XeveContext, x)
545 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
546
551 };
552
553 // Consider using following options (./ffmpeg --help encoder=libxeve)
554 //
556 {
"preset",
"Encoding preset for setting encoding speed",
OFFSET(preset_id),
AV_OPT_TYPE_INT, { .i64 = XEVE_PRESET_MEDIUM }, XEVE_PRESET_DEFAULT, XEVE_PRESET_PLACEBO,
VE, .unit =
"preset" },
557 {
"default",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = XEVE_PRESET_DEFAULT }, INT_MIN, INT_MAX,
VE, .unit =
"preset" },
559 {
"medium",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = XEVE_PRESET_MEDIUM }, INT_MIN, INT_MAX,
VE, .unit =
"preset" },
561 {
"placebo",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = XEVE_PRESET_PLACEBO }, INT_MIN, INT_MAX,
VE, .unit =
"preset" },
562 {
"tune",
"Tuning parameter for special purpose operation",
OFFSET(tune_id),
AV_OPT_TYPE_INT, { .i64 = XEVE_TUNE_NONE }, XEVE_TUNE_NONE, XEVE_TUNE_PSNR,
VE, .unit =
"tune"},
564 {
"zerolatency",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = XEVE_TUNE_ZEROLATENCY }, INT_MIN, INT_MAX,
VE, .unit =
"tune" },
566 {
"profile",
"Encoding profile",
OFFSET(profile_id),
AV_OPT_TYPE_INT, { .i64 = XEVE_PROFILE_BASELINE }, XEVE_PROFILE_BASELINE, XEVE_PROFILE_MAIN,
VE, .unit =
"profile" },
567 {
"baseline",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = XEVE_PROFILE_BASELINE }, INT_MIN, INT_MAX,
VE, .unit =
"profile" },
573 {
"qp",
"Quantization parameter value for CQP rate control mode",
OFFSET(qp),
AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51,
VE },
574 {
"crf",
"Constant rate factor value for CRF rate control mode",
OFFSET(crf),
AV_OPT_TYPE_INT, { .i64 = 32 }, 10, 49,
VE },
575 {
"hash",
"Embed picture signature (HASH) for conformance checking in decoding",
OFFSET(
hash),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1,
VE },
576 {
"sei_info",
"Embed SEI messages identifying encoder parameters and command line arguments",
OFFSET(sei_info),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1,
VE },
577 {
"xeve-params",
"Override the xeve configuration using a :-separated list of key=value parameters",
OFFSET(xeve_params),
AV_OPT_TYPE_DICT, { 0 }, 0, 0,
VE },
579 };
580
586 };
587
588 /**
589 * libavcodec generic global options, which can be set on all the encoders and decoders
590 * @see https://www.ffmpeg.org/ffmpeg-codecs.html#Codec-Options
591 */
593 { "b", "0" }, // bitrate in terms of kilo-bits per second
594 { "g", "0" }, // gop_size (key-frame interval 0: only one I-frame at the first time; 1: every frame is coded in I-frame)
595 { "bf", "15"}, // maximum number of B frames (0: no B-frames, 1,3,7,15)
596 { "threads", "0"}, // number of threads to be used (0: automatically select the number of threads to set)
598 };
599
613 .p.wrapper_name = "libxeve",
616 };