1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * AVS2 encoding using the xavs2 library 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (C) 2018 Yiqun Xu, <yiqun.xu@vipl.ict.ac.cn> 5cabdff1aSopenharmony_ci * Falei Luo, <falei.luo@gmail.com> 6cabdff1aSopenharmony_ci * Huiwen Ren, <hwrenx@gmail.com> 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * This file is part of FFmpeg. 9cabdff1aSopenharmony_ci * 10cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 11cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 12cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 13cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 14cabdff1aSopenharmony_ci * 15cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 16cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 17cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18cabdff1aSopenharmony_ci * Lesser General Public License for more details. 19cabdff1aSopenharmony_ci * 20cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 21cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 22cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23cabdff1aSopenharmony_ci */ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "xavs2.h" 26cabdff1aSopenharmony_ci#include "codec_internal.h" 27cabdff1aSopenharmony_ci#include "encode.h" 28cabdff1aSopenharmony_ci#include "mpeg12.h" 29cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 30cabdff1aSopenharmony_ci#include "libavutil/opt.h" 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_ci#define xavs2_opt_set2(name, format, ...) do{ \ 33cabdff1aSopenharmony_ci char opt_str[16] = {0}; \ 34cabdff1aSopenharmony_ci int err; \ 35cabdff1aSopenharmony_ci av_strlcatf(opt_str, sizeof(opt_str), format, __VA_ARGS__); \ 36cabdff1aSopenharmony_ci err = cae->api->opt_set2(cae->param, name, opt_str); \ 37cabdff1aSopenharmony_ci if (err < 0) {\ 38cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "Invalid value for %s: %s\n", name, opt_str);\ 39cabdff1aSopenharmony_ci }\ 40cabdff1aSopenharmony_ci} while(0); 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_citypedef struct XAVS2EContext { 43cabdff1aSopenharmony_ci AVClass *class; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci int lcu_row_threads; 46cabdff1aSopenharmony_ci int initial_qp; 47cabdff1aSopenharmony_ci int qp; 48cabdff1aSopenharmony_ci int max_qp; 49cabdff1aSopenharmony_ci int min_qp; 50cabdff1aSopenharmony_ci int preset_level; 51cabdff1aSopenharmony_ci int log_level; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci void *encoder; 54cabdff1aSopenharmony_ci AVDictionary *xavs2_opts; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci xavs2_outpacket_t packet; 57cabdff1aSopenharmony_ci xavs2_param_t *param; 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci const xavs2_api_t *api; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci} XAVS2EContext; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_cistatic av_cold int xavs2_init(AVCodecContext *avctx) 64cabdff1aSopenharmony_ci{ 65cabdff1aSopenharmony_ci XAVS2EContext *cae = avctx->priv_data; 66cabdff1aSopenharmony_ci int bit_depth, code; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci bit_depth = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? 8 : 10; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci /* get API handler */ 71cabdff1aSopenharmony_ci cae->api = xavs2_api_get(bit_depth); 72cabdff1aSopenharmony_ci if (!cae->api) { 73cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to get xavs2 api context\n"); 74cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 75cabdff1aSopenharmony_ci } 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci cae->param = cae->api->opt_alloc(); 78cabdff1aSopenharmony_ci if (!cae->param) { 79cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to alloc xavs2 parameters\n"); 80cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 81cabdff1aSopenharmony_ci } 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci xavs2_opt_set2("Width", "%d", avctx->width); 84cabdff1aSopenharmony_ci xavs2_opt_set2("Height", "%d", avctx->height); 85cabdff1aSopenharmony_ci xavs2_opt_set2("BFrames", "%d", avctx->max_b_frames); 86cabdff1aSopenharmony_ci xavs2_opt_set2("BitDepth", "%d", bit_depth); 87cabdff1aSopenharmony_ci xavs2_opt_set2("Log", "%d", cae->log_level); 88cabdff1aSopenharmony_ci xavs2_opt_set2("Preset", "%d", cae->preset_level); 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci xavs2_opt_set2("IntraPeriodMax", "%d", avctx->gop_size); 91cabdff1aSopenharmony_ci xavs2_opt_set2("IntraPeriodMin", "%d", avctx->gop_size); 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci xavs2_opt_set2("ThreadFrames", "%d", avctx->thread_count); 94cabdff1aSopenharmony_ci xavs2_opt_set2("ThreadRows", "%d", cae->lcu_row_threads); 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci xavs2_opt_set2("OpenGOP", "%d", !(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)); 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci { 99cabdff1aSopenharmony_ci AVDictionaryEntry *en = NULL; 100cabdff1aSopenharmony_ci while ((en = av_dict_get(cae->xavs2_opts, "", en, AV_DICT_IGNORE_SUFFIX))) 101cabdff1aSopenharmony_ci xavs2_opt_set2(en->key, "%s", en->value); 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci /* Rate control */ 105cabdff1aSopenharmony_ci if (avctx->bit_rate > 0) { 106cabdff1aSopenharmony_ci xavs2_opt_set2("RateControl", "%d", 1); 107cabdff1aSopenharmony_ci xavs2_opt_set2("TargetBitRate", "%"PRId64"", avctx->bit_rate); 108cabdff1aSopenharmony_ci xavs2_opt_set2("InitialQP", "%d", cae->initial_qp); 109cabdff1aSopenharmony_ci xavs2_opt_set2("MaxQP", "%d", avctx->qmax >= 0 ? avctx->qmax : cae->max_qp); 110cabdff1aSopenharmony_ci xavs2_opt_set2("MinQP", "%d", avctx->qmin >= 0 ? avctx->qmin : cae->min_qp); 111cabdff1aSopenharmony_ci } else { 112cabdff1aSopenharmony_ci xavs2_opt_set2("InitialQP", "%d", cae->qp); 113cabdff1aSopenharmony_ci } 114cabdff1aSopenharmony_ci 115cabdff1aSopenharmony_ci ff_mpeg12_find_best_frame_rate(avctx->framerate, &code, NULL, NULL, 0); 116cabdff1aSopenharmony_ci xavs2_opt_set2("FrameRate", "%d", code); 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci cae->encoder = cae->api->encoder_create(cae->param); 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci if (!cae->encoder) { 121cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to create xavs2 encoder instance.\n"); 122cabdff1aSopenharmony_ci return AVERROR(EINVAL); 123cabdff1aSopenharmony_ci } 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci return 0; 126cabdff1aSopenharmony_ci} 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_cistatic void xavs2_copy_frame_with_shift(xavs2_picture_t *pic, const AVFrame *frame, const int shift_in) 129cabdff1aSopenharmony_ci{ 130cabdff1aSopenharmony_ci uint16_t *p_plane; 131cabdff1aSopenharmony_ci uint8_t *p_buffer; 132cabdff1aSopenharmony_ci int plane; 133cabdff1aSopenharmony_ci int hIdx; 134cabdff1aSopenharmony_ci int wIdx; 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci for (plane = 0; plane < 3; plane++) { 137cabdff1aSopenharmony_ci p_plane = (uint16_t *)pic->img.img_planes[plane]; 138cabdff1aSopenharmony_ci p_buffer = frame->data[plane]; 139cabdff1aSopenharmony_ci for (hIdx = 0; hIdx < pic->img.i_lines[plane]; hIdx++) { 140cabdff1aSopenharmony_ci memset(p_plane, 0, pic->img.i_stride[plane]); 141cabdff1aSopenharmony_ci for (wIdx = 0; wIdx < pic->img.i_width[plane]; wIdx++) { 142cabdff1aSopenharmony_ci p_plane[wIdx] = p_buffer[wIdx] << shift_in; 143cabdff1aSopenharmony_ci } 144cabdff1aSopenharmony_ci p_plane += pic->img.i_stride[plane]; 145cabdff1aSopenharmony_ci p_buffer += frame->linesize[plane]; 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci} 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_cistatic void xavs2_copy_frame(xavs2_picture_t *pic, const AVFrame *frame) 151cabdff1aSopenharmony_ci{ 152cabdff1aSopenharmony_ci uint8_t *p_plane; 153cabdff1aSopenharmony_ci uint8_t *p_buffer; 154cabdff1aSopenharmony_ci int plane; 155cabdff1aSopenharmony_ci int hIdx; 156cabdff1aSopenharmony_ci int stride; 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci for (plane = 0; plane < 3; plane++) { 159cabdff1aSopenharmony_ci p_plane = pic->img.img_planes[plane]; 160cabdff1aSopenharmony_ci p_buffer = frame->data[plane]; 161cabdff1aSopenharmony_ci stride = pic->img.i_width[plane] * pic->img.in_sample_size; 162cabdff1aSopenharmony_ci for (hIdx = 0; hIdx < pic->img.i_lines[plane]; hIdx++) { 163cabdff1aSopenharmony_ci memcpy(p_plane, p_buffer, stride); 164cabdff1aSopenharmony_ci p_plane += pic->img.i_stride[plane]; 165cabdff1aSopenharmony_ci p_buffer += frame->linesize[plane]; 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci} 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_cistatic int xavs2_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 171cabdff1aSopenharmony_ci const AVFrame *frame, int *got_packet) 172cabdff1aSopenharmony_ci{ 173cabdff1aSopenharmony_ci XAVS2EContext *cae = avctx->priv_data; 174cabdff1aSopenharmony_ci xavs2_picture_t pic; 175cabdff1aSopenharmony_ci int ret; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci /* create the XAVS2 video encoder */ 178cabdff1aSopenharmony_ci /* read frame data and send to the XAVS2 video encoder */ 179cabdff1aSopenharmony_ci if (cae->api->encoder_get_buffer(cae->encoder, &pic) < 0) { 180cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to get xavs2 frame buffer\n"); 181cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci if (frame) { 184cabdff1aSopenharmony_ci switch (frame->format) { 185cabdff1aSopenharmony_ci case AV_PIX_FMT_YUV420P: 186cabdff1aSopenharmony_ci if (pic.img.in_sample_size == pic.img.enc_sample_size) { 187cabdff1aSopenharmony_ci xavs2_copy_frame(&pic, frame); 188cabdff1aSopenharmony_ci } else { 189cabdff1aSopenharmony_ci const int shift_in = atoi(cae->api->opt_get(cae->param, "SampleShift")); 190cabdff1aSopenharmony_ci xavs2_copy_frame_with_shift(&pic, frame, shift_in); 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci break; 193cabdff1aSopenharmony_ci case AV_PIX_FMT_YUV420P10: 194cabdff1aSopenharmony_ci if (pic.img.in_sample_size == pic.img.enc_sample_size) { 195cabdff1aSopenharmony_ci xavs2_copy_frame(&pic, frame); 196cabdff1aSopenharmony_ci break; 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci default: 199cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format\n"); 200cabdff1aSopenharmony_ci return AVERROR(EINVAL); 201cabdff1aSopenharmony_ci break; 202cabdff1aSopenharmony_ci } 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci pic.i_state = 0; 205cabdff1aSopenharmony_ci pic.i_pts = frame->pts; 206cabdff1aSopenharmony_ci pic.i_type = XAVS2_TYPE_AUTO; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci ret = cae->api->encoder_encode(cae->encoder, &pic, &cae->packet); 209cabdff1aSopenharmony_ci 210cabdff1aSopenharmony_ci if (ret) { 211cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Encoding error occurred.\n"); 212cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 213cabdff1aSopenharmony_ci } 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci } else { 216cabdff1aSopenharmony_ci cae->api->encoder_encode(cae->encoder, NULL, &cae->packet); 217cabdff1aSopenharmony_ci } 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_ci if ((cae->packet.len) && (cae->packet.state != XAVS2_STATE_FLUSH_END)) { 220cabdff1aSopenharmony_ci if ((ret = ff_get_encode_buffer(avctx, pkt, cae->packet.len, 0)) < 0) { 221cabdff1aSopenharmony_ci cae->api->encoder_packet_unref(cae->encoder, &cae->packet); 222cabdff1aSopenharmony_ci return ret; 223cabdff1aSopenharmony_ci } 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci pkt->pts = cae->packet.pts; 226cabdff1aSopenharmony_ci pkt->dts = cae->packet.dts; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci if (cae->packet.type == XAVS2_TYPE_IDR || 229cabdff1aSopenharmony_ci cae->packet.type == XAVS2_TYPE_I || 230cabdff1aSopenharmony_ci cae->packet.type == XAVS2_TYPE_KEYFRAME) { 231cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 232cabdff1aSopenharmony_ci } 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci memcpy(pkt->data, cae->packet.stream, cae->packet.len); 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci cae->api->encoder_packet_unref(cae->encoder, &cae->packet); 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci *got_packet = 1; 239cabdff1aSopenharmony_ci } else { 240cabdff1aSopenharmony_ci *got_packet = 0; 241cabdff1aSopenharmony_ci } 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci return 0; 244cabdff1aSopenharmony_ci} 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_cistatic av_cold int xavs2_close(AVCodecContext *avctx) 247cabdff1aSopenharmony_ci{ 248cabdff1aSopenharmony_ci XAVS2EContext *cae = avctx->priv_data; 249cabdff1aSopenharmony_ci /* destroy the encoder */ 250cabdff1aSopenharmony_ci if (cae->api) { 251cabdff1aSopenharmony_ci cae->api->encoder_destroy(cae->encoder); 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_ci if (cae->param) { 254cabdff1aSopenharmony_ci cae->api->opt_destroy(cae->param); 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci return 0; 258cabdff1aSopenharmony_ci} 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(XAVS2EContext, x) 261cabdff1aSopenharmony_ci#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_cistatic const AVOption options[] = { 264cabdff1aSopenharmony_ci { "lcu_row_threads" , "number of parallel threads for rows" , OFFSET(lcu_row_threads) , AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, VE }, 265cabdff1aSopenharmony_ci { "initial_qp" , "Quantization initial parameter" , OFFSET(initial_qp) , AV_OPT_TYPE_INT, {.i64 = 34 }, 1, 63, VE }, 266cabdff1aSopenharmony_ci { "qp" , "Quantization parameter" , OFFSET(qp) , AV_OPT_TYPE_INT, {.i64 = 34 }, 1, 63, VE }, 267cabdff1aSopenharmony_ci { "max_qp" , "max qp for rate control" , OFFSET(max_qp) , AV_OPT_TYPE_INT, {.i64 = 55 }, 0, 63, VE }, 268cabdff1aSopenharmony_ci { "min_qp" , "min qp for rate control" , OFFSET(min_qp) , AV_OPT_TYPE_INT, {.i64 = 20 }, 0, 63, VE }, 269cabdff1aSopenharmony_ci { "speed_level" , "Speed level, higher is better but slower", OFFSET(preset_level) , AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 9, VE }, 270cabdff1aSopenharmony_ci { "log_level" , "log level: -1: none, 0: error, 1: warning, 2: info, 3: debug", OFFSET(log_level) , AV_OPT_TYPE_INT, {.i64 = 0 }, -1, 3, VE }, 271cabdff1aSopenharmony_ci { "xavs2-params" , "set the xavs2 configuration using a :-separated list of key=value parameters", OFFSET(xavs2_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, 272cabdff1aSopenharmony_ci { NULL }, 273cabdff1aSopenharmony_ci}; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_cistatic const AVClass libxavs2 = { 276cabdff1aSopenharmony_ci .class_name = "XAVS2EContext", 277cabdff1aSopenharmony_ci .item_name = av_default_item_name, 278cabdff1aSopenharmony_ci .option = options, 279cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 280cabdff1aSopenharmony_ci}; 281cabdff1aSopenharmony_ci 282cabdff1aSopenharmony_cistatic const FFCodecDefault xavs2_defaults[] = { 283cabdff1aSopenharmony_ci { "b", "0" }, 284cabdff1aSopenharmony_ci { "g", "48"}, 285cabdff1aSopenharmony_ci { "bf", "7" }, 286cabdff1aSopenharmony_ci { NULL }, 287cabdff1aSopenharmony_ci}; 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ciconst FFCodec ff_libxavs2_encoder = { 290cabdff1aSopenharmony_ci .p.name = "libxavs2", 291cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("libxavs2 AVS2-P2/IEEE1857.4"), 292cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 293cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_AVS2, 294cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | 295cabdff1aSopenharmony_ci AV_CODEC_CAP_OTHER_THREADS, 296cabdff1aSopenharmony_ci .priv_data_size = sizeof(XAVS2EContext), 297cabdff1aSopenharmony_ci .init = xavs2_init, 298cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(xavs2_encode_frame), 299cabdff1aSopenharmony_ci .close = xavs2_close, 300cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_AUTO_THREADS, 301cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, 302cabdff1aSopenharmony_ci AV_PIX_FMT_NONE }, 303cabdff1aSopenharmony_ci .p.priv_class = &libxavs2, 304cabdff1aSopenharmony_ci .defaults = xavs2_defaults, 305cabdff1aSopenharmony_ci .p.wrapper_name = "libxavs2", 306cabdff1aSopenharmony_ci} ; 307