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