vaapi_encode: Add common options between all encoders
[ffmpeg.git] / libavcodec / vaapi_encode_vp9.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <va/va.h>
20 #include <va/va_enc_vp9.h>
21
22 #include "libavutil/avassert.h"
23 #include "libavutil/common.h"
24 #include "libavutil/internal.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/pixfmt.h"
27
28 #include "avcodec.h"
29 #include "internal.h"
30 #include "vaapi_encode.h"
31
32 #define VP9_MAX_QUANT 255
33
34
35 typedef struct VAAPIEncodeVP9Context {
36     VAAPIEncodeContext common;
37
38     // User options.
39     int loop_filter_level;
40     int loop_filter_sharpness;
41
42     // Derived settings.
43     int q_idx_idr;
44     int q_idx_p;
45     int q_idx_b;
46
47     // Stream state.
48
49     // Reference direction for B-like frames:
50     // 0 - most recent P/IDR frame is last.
51     // 1 - most recent P frame is golden.
52     int last_ref_dir;
53 } VAAPIEncodeVP9Context;
54
55
56 #define vseq_var(name)     vseq->name, name
57 #define vseq_field(name)   vseq->seq_fields.bits.name, name
58 #define vpic_var(name)     vpic->name, name
59 #define vpic_field(name)   vpic->pic_fields.bits.name, name
60
61
62 static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx)
63 {
64     VAAPIEncodeContext               *ctx = avctx->priv_data;
65     VAEncSequenceParameterBufferVP9 *vseq = ctx->codec_sequence_params;
66     VAEncPictureParameterBufferVP9  *vpic = ctx->codec_picture_params;
67
68     vseq->max_frame_width  = avctx->width;
69     vseq->max_frame_height = avctx->height;
70
71     vseq->kf_auto = 0;
72
73     if (!(ctx->va_rc_mode & VA_RC_CQP)) {
74         vseq->bits_per_second = avctx->bit_rate;
75         vseq->intra_period    = avctx->gop_size;
76     }
77
78     vpic->frame_width_src  = avctx->width;
79     vpic->frame_height_src = avctx->height;
80     vpic->frame_width_dst  = avctx->width;
81     vpic->frame_height_dst = avctx->height;
82
83     return 0;
84 }
85
86 static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
87                                                 VAAPIEncodePicture *pic)
88 {
89     VAAPIEncodeVP9Context          *priv = avctx->priv_data;
90     VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params;
91     int i;
92
93     vpic->reconstructed_frame = pic->recon_surface;
94     vpic->coded_buf = pic->output_buffer;
95
96     switch (pic->type) {
97     case PICTURE_TYPE_IDR:
98         av_assert0(pic->nb_refs == 0);
99         vpic->ref_flags.bits.force_kf = 1;
100         vpic->refresh_frame_flags = 0x01;
101         priv->last_ref_dir = 0;
102         break;
103     case PICTURE_TYPE_P:
104         av_assert0(pic->nb_refs == 1);
105         if (avctx->max_b_frames > 0) {
106             if (priv->last_ref_dir) {
107                 vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
108                 vpic->ref_flags.bits.ref_gf_idx         = 1;
109                 vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
110                 vpic->refresh_frame_flags = 0x01;
111             } else {
112                 vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
113                 vpic->ref_flags.bits.ref_last_idx       = 0;
114                 vpic->ref_flags.bits.ref_last_sign_bias = 1;
115                 vpic->refresh_frame_flags = 0x02;
116             }
117         } else {
118             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
119             vpic->ref_flags.bits.ref_last_idx       = 0;
120             vpic->ref_flags.bits.ref_last_sign_bias = 1;
121             vpic->refresh_frame_flags = 0x01;
122         }
123         break;
124     case PICTURE_TYPE_B:
125         av_assert0(pic->nb_refs == 2);
126         if (priv->last_ref_dir) {
127             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
128             vpic->ref_flags.bits.ref_frame_ctrl_l1  = 2;
129             vpic->ref_flags.bits.ref_last_idx       = 0;
130             vpic->ref_flags.bits.ref_last_sign_bias = 1;
131             vpic->ref_flags.bits.ref_gf_idx         = 1;
132             vpic->ref_flags.bits.ref_gf_sign_bias   = 0;
133         } else {
134             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
135             vpic->ref_flags.bits.ref_frame_ctrl_l1  = 1;
136             vpic->ref_flags.bits.ref_last_idx       = 0;
137             vpic->ref_flags.bits.ref_last_sign_bias = 0;
138             vpic->ref_flags.bits.ref_gf_idx         = 1;
139             vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
140         }
141         vpic->refresh_frame_flags = 0x00;
142         break;
143     default:
144         av_assert0(0 && "invalid picture type");
145     }
146
147     for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
148         vpic->reference_frames[i] = VA_INVALID_SURFACE;
149     if (pic->type == PICTURE_TYPE_P) {
150         av_assert0(pic->refs[0]);
151         vpic->reference_frames[priv->last_ref_dir] =
152             pic->refs[0]->recon_surface;
153     } else if (pic->type == PICTURE_TYPE_B) {
154         av_assert0(pic->refs[0] && pic->refs[1]);
155         vpic->reference_frames[!priv->last_ref_dir] =
156             pic->refs[0]->recon_surface;
157         vpic->reference_frames[priv->last_ref_dir] =
158             pic->refs[1]->recon_surface;
159     }
160
161     vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR);
162     vpic->pic_flags.bits.show_frame = pic->display_order <= pic->encode_order;
163
164     if (pic->type == PICTURE_TYPE_IDR)
165         vpic->luma_ac_qindex     = priv->q_idx_idr;
166     else if (pic->type == PICTURE_TYPE_P)
167         vpic->luma_ac_qindex     = priv->q_idx_p;
168     else
169         vpic->luma_ac_qindex     = priv->q_idx_b;
170     vpic->luma_dc_qindex_delta   = 0;
171     vpic->chroma_ac_qindex_delta = 0;
172     vpic->chroma_dc_qindex_delta = 0;
173
174     vpic->filter_level    = priv->loop_filter_level;
175     vpic->sharpness_level = priv->loop_filter_sharpness;
176
177     if (avctx->max_b_frames > 0 && pic->type == PICTURE_TYPE_P)
178         priv->last_ref_dir = !priv->last_ref_dir;
179
180     return 0;
181 }
182
183 static av_cold int vaapi_encode_vp9_configure(AVCodecContext *avctx)
184 {
185     VAAPIEncodeVP9Context *priv = avctx->priv_data;
186
187     priv->q_idx_p = av_clip(avctx->global_quality, 0, VP9_MAX_QUANT);
188     if (avctx->i_quant_factor > 0.0)
189         priv->q_idx_idr = av_clip((avctx->global_quality *
190                                    avctx->i_quant_factor +
191                                    avctx->i_quant_offset) + 0.5,
192                                   0, VP9_MAX_QUANT);
193     else
194         priv->q_idx_idr = priv->q_idx_p;
195     if (avctx->b_quant_factor > 0.0)
196         priv->q_idx_b = av_clip((avctx->global_quality *
197                                  avctx->b_quant_factor +
198                                  avctx->b_quant_offset) + 0.5,
199                                 0, VP9_MAX_QUANT);
200     else
201         priv->q_idx_b = priv->q_idx_p;
202
203     return 0;
204 }
205
206 static const VAAPIEncodeProfile vaapi_encode_vp9_profiles[] = {
207     { FF_PROFILE_VP9_0,  8, 3, 1, 1, VAProfileVP9Profile0 },
208     { FF_PROFILE_VP9_2, 10, 3, 1, 1, VAProfileVP9Profile2 },
209     { FF_PROFILE_UNKNOWN }
210 };
211
212 static const VAAPIEncodeType vaapi_encode_type_vp9 = {
213     .profiles              = vaapi_encode_vp9_profiles,
214
215     .configure             = &vaapi_encode_vp9_configure,
216
217     .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP9),
218     .init_sequence_params  = &vaapi_encode_vp9_init_sequence_params,
219
220     .picture_params_size   = sizeof(VAEncPictureParameterBufferVP9),
221     .init_picture_params   = &vaapi_encode_vp9_init_picture_params,
222 };
223
224 static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx)
225 {
226     VAAPIEncodeContext *ctx = avctx->priv_data;
227
228     ctx->codec = &vaapi_encode_type_vp9;
229
230     if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
231         ctx->va_rc_mode = VA_RC_CQP;
232     } else if (avctx->bit_rate > 0) {
233         if (avctx->bit_rate == avctx->rc_max_rate)
234             ctx->va_rc_mode = VA_RC_CBR;
235         else
236             ctx->va_rc_mode = VA_RC_VBR;
237     } else {
238         ctx->va_rc_mode = VA_RC_CQP;
239     }
240
241     // Packed headers are not currently supported.
242     ctx->va_packed_headers = 0;
243
244     // Surfaces must be aligned to superblock boundaries.
245     ctx->surface_width  = FFALIGN(avctx->width,  64);
246     ctx->surface_height = FFALIGN(avctx->height, 64);
247
248     return ff_vaapi_encode_init(avctx);
249 }
250
251 #define OFFSET(x) offsetof(VAAPIEncodeVP9Context, x)
252 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
253 static const AVOption vaapi_encode_vp9_options[] = {
254     VAAPI_ENCODE_COMMON_OPTIONS,
255     { "loop_filter_level", "Loop filter level",
256       OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS },
257     { "loop_filter_sharpness", "Loop filter sharpness",
258       OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, FLAGS },
259     { NULL },
260 };
261
262 static const AVCodecDefault vaapi_encode_vp9_defaults[] = {
263     { "b",              "0"   },
264     { "bf",             "0"   },
265     { "g",              "250" },
266     { "global_quality", "100" },
267     { NULL },
268 };
269
270 static const AVClass vaapi_encode_vp9_class = {
271     .class_name = "vp9_vaapi",
272     .item_name  = av_default_item_name,
273     .option     = vaapi_encode_vp9_options,
274     .version    = LIBAVUTIL_VERSION_INT,
275 };
276
277 AVCodec ff_vp9_vaapi_encoder = {
278     .name           = "vp9_vaapi",
279     .long_name      = NULL_IF_CONFIG_SMALL("VP9 (VAAPI)"),
280     .type           = AVMEDIA_TYPE_VIDEO,
281     .id             = AV_CODEC_ID_VP9,
282     .priv_data_size = sizeof(VAAPIEncodeVP9Context),
283     .init           = &vaapi_encode_vp9_init,
284     .encode2        = &ff_vaapi_encode2,
285     .close          = &ff_vaapi_encode_close,
286     .priv_class     = &vaapi_encode_vp9_class,
287     .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
288     .defaults       = vaapi_encode_vp9_defaults,
289     .pix_fmts = (const enum AVPixelFormat[]) {
290         AV_PIX_FMT_VAAPI,
291         AV_PIX_FMT_NONE,
292     },
293     .wrapper_name   = "vaapi",
294 };