vaapi_encode: Clean up the GOP structure configuration
[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 = ctx->va_bit_rate;
75         vseq->intra_period    = ctx->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     VAAPIEncodeContext              *ctx = avctx->priv_data;
90     VAAPIEncodeVP9Context          *priv = avctx->priv_data;
91     VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params;
92     int i;
93
94     vpic->reconstructed_frame = pic->recon_surface;
95     vpic->coded_buf = pic->output_buffer;
96
97     switch (pic->type) {
98     case PICTURE_TYPE_IDR:
99         av_assert0(pic->nb_refs == 0);
100         vpic->ref_flags.bits.force_kf = 1;
101         vpic->refresh_frame_flags = 0x01;
102         priv->last_ref_dir = 0;
103         break;
104     case PICTURE_TYPE_P:
105         av_assert0(pic->nb_refs == 1);
106         if (ctx->b_per_p > 0) {
107             if (priv->last_ref_dir) {
108                 vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
109                 vpic->ref_flags.bits.ref_gf_idx         = 1;
110                 vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
111                 vpic->refresh_frame_flags = 0x01;
112             } else {
113                 vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
114                 vpic->ref_flags.bits.ref_last_idx       = 0;
115                 vpic->ref_flags.bits.ref_last_sign_bias = 1;
116                 vpic->refresh_frame_flags = 0x02;
117             }
118         } else {
119             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
120             vpic->ref_flags.bits.ref_last_idx       = 0;
121             vpic->ref_flags.bits.ref_last_sign_bias = 1;
122             vpic->refresh_frame_flags = 0x01;
123         }
124         break;
125     case PICTURE_TYPE_B:
126         av_assert0(pic->nb_refs == 2);
127         if (priv->last_ref_dir) {
128             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
129             vpic->ref_flags.bits.ref_frame_ctrl_l1  = 2;
130             vpic->ref_flags.bits.ref_last_idx       = 0;
131             vpic->ref_flags.bits.ref_last_sign_bias = 1;
132             vpic->ref_flags.bits.ref_gf_idx         = 1;
133             vpic->ref_flags.bits.ref_gf_sign_bias   = 0;
134         } else {
135             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
136             vpic->ref_flags.bits.ref_frame_ctrl_l1  = 1;
137             vpic->ref_flags.bits.ref_last_idx       = 0;
138             vpic->ref_flags.bits.ref_last_sign_bias = 0;
139             vpic->ref_flags.bits.ref_gf_idx         = 1;
140             vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
141         }
142         vpic->refresh_frame_flags = 0x00;
143         break;
144     default:
145         av_assert0(0 && "invalid picture type");
146     }
147
148     for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
149         vpic->reference_frames[i] = VA_INVALID_SURFACE;
150     if (pic->type == PICTURE_TYPE_P) {
151         av_assert0(pic->refs[0]);
152         vpic->reference_frames[priv->last_ref_dir] =
153             pic->refs[0]->recon_surface;
154     } else if (pic->type == PICTURE_TYPE_B) {
155         av_assert0(pic->refs[0] && pic->refs[1]);
156         vpic->reference_frames[!priv->last_ref_dir] =
157             pic->refs[0]->recon_surface;
158         vpic->reference_frames[priv->last_ref_dir] =
159             pic->refs[1]->recon_surface;
160     }
161
162     vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR);
163     vpic->pic_flags.bits.show_frame = pic->display_order <= pic->encode_order;
164
165     if (pic->type == PICTURE_TYPE_IDR)
166         vpic->luma_ac_qindex     = priv->q_idx_idr;
167     else if (pic->type == PICTURE_TYPE_P)
168         vpic->luma_ac_qindex     = priv->q_idx_p;
169     else
170         vpic->luma_ac_qindex     = priv->q_idx_b;
171     vpic->luma_dc_qindex_delta   = 0;
172     vpic->chroma_ac_qindex_delta = 0;
173     vpic->chroma_dc_qindex_delta = 0;
174
175     vpic->filter_level    = priv->loop_filter_level;
176     vpic->sharpness_level = priv->loop_filter_sharpness;
177
178     if (ctx->b_per_p > 0 && pic->type == PICTURE_TYPE_P)
179         priv->last_ref_dir = !priv->last_ref_dir;
180
181     return 0;
182 }
183
184 static av_cold int vaapi_encode_vp9_configure(AVCodecContext *avctx)
185 {
186     VAAPIEncodeVP9Context *priv = avctx->priv_data;
187
188     priv->q_idx_p = av_clip(avctx->global_quality, 0, VP9_MAX_QUANT);
189     if (avctx->i_quant_factor > 0.0)
190         priv->q_idx_idr = av_clip((avctx->global_quality *
191                                    avctx->i_quant_factor +
192                                    avctx->i_quant_offset) + 0.5,
193                                   0, VP9_MAX_QUANT);
194     else
195         priv->q_idx_idr = priv->q_idx_p;
196     if (avctx->b_quant_factor > 0.0)
197         priv->q_idx_b = av_clip((avctx->global_quality *
198                                  avctx->b_quant_factor +
199                                  avctx->b_quant_offset) + 0.5,
200                                 0, VP9_MAX_QUANT);
201     else
202         priv->q_idx_b = priv->q_idx_p;
203
204     return 0;
205 }
206
207 static const VAAPIEncodeProfile vaapi_encode_vp9_profiles[] = {
208     { FF_PROFILE_VP9_0,  8, 3, 1, 1, VAProfileVP9Profile0 },
209     { FF_PROFILE_VP9_2, 10, 3, 1, 1, VAProfileVP9Profile2 },
210     { FF_PROFILE_UNKNOWN }
211 };
212
213 static const VAAPIEncodeType vaapi_encode_type_vp9 = {
214     .profiles              = vaapi_encode_vp9_profiles,
215
216     .configure             = &vaapi_encode_vp9_configure,
217
218     .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP9),
219     .init_sequence_params  = &vaapi_encode_vp9_init_sequence_params,
220
221     .picture_params_size   = sizeof(VAEncPictureParameterBufferVP9),
222     .init_picture_params   = &vaapi_encode_vp9_init_picture_params,
223 };
224
225 static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx)
226 {
227     VAAPIEncodeContext *ctx = avctx->priv_data;
228
229     ctx->codec = &vaapi_encode_type_vp9;
230
231     // Packed headers are not currently supported.
232     ctx->va_packed_headers = 0;
233
234     // Surfaces must be aligned to superblock boundaries.
235     ctx->surface_width  = FFALIGN(avctx->width,  64);
236     ctx->surface_height = FFALIGN(avctx->height, 64);
237
238     return ff_vaapi_encode_init(avctx);
239 }
240
241 #define OFFSET(x) offsetof(VAAPIEncodeVP9Context, x)
242 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
243 static const AVOption vaapi_encode_vp9_options[] = {
244     VAAPI_ENCODE_COMMON_OPTIONS,
245     { "loop_filter_level", "Loop filter level",
246       OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS },
247     { "loop_filter_sharpness", "Loop filter sharpness",
248       OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, FLAGS },
249     { NULL },
250 };
251
252 static const AVCodecDefault vaapi_encode_vp9_defaults[] = {
253     { "b",              "0"   },
254     { "bf",             "0"   },
255     { "g",              "250" },
256     { "global_quality", "100" },
257     { "qmin",           "-1"  },
258     { "qmax",           "-1"  },
259     { NULL },
260 };
261
262 static const AVClass vaapi_encode_vp9_class = {
263     .class_name = "vp9_vaapi",
264     .item_name  = av_default_item_name,
265     .option     = vaapi_encode_vp9_options,
266     .version    = LIBAVUTIL_VERSION_INT,
267 };
268
269 AVCodec ff_vp9_vaapi_encoder = {
270     .name           = "vp9_vaapi",
271     .long_name      = NULL_IF_CONFIG_SMALL("VP9 (VAAPI)"),
272     .type           = AVMEDIA_TYPE_VIDEO,
273     .id             = AV_CODEC_ID_VP9,
274     .priv_data_size = sizeof(VAAPIEncodeVP9Context),
275     .init           = &vaapi_encode_vp9_init,
276     .encode2        = &ff_vaapi_encode2,
277     .close          = &ff_vaapi_encode_close,
278     .priv_class     = &vaapi_encode_vp9_class,
279     .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
280     .defaults       = vaapi_encode_vp9_defaults,
281     .pix_fmts = (const enum AVPixelFormat[]) {
282         AV_PIX_FMT_VAAPI,
283         AV_PIX_FMT_NONE,
284     },
285     .wrapper_name   = "vaapi",
286 };