]> git.sesse.net Git - ffmpeg/blob - libavcodec/vaapi_encode_vp9.c
Merge commit '141c960e21d2860e354f9b90df136184dd00a9a8'
[ffmpeg] / 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 VAAPIEncodeType vaapi_encode_type_vp9 = {
207     .configure             = &vaapi_encode_vp9_configure,
208
209     .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP9),
210     .init_sequence_params  = &vaapi_encode_vp9_init_sequence_params,
211
212     .picture_params_size   = sizeof(VAEncPictureParameterBufferVP9),
213     .init_picture_params   = &vaapi_encode_vp9_init_picture_params,
214 };
215
216 static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx)
217 {
218     VAAPIEncodeContext *ctx = avctx->priv_data;
219
220     ctx->codec = &vaapi_encode_type_vp9;
221
222     switch (avctx->profile) {
223     case FF_PROFILE_VP9_0:
224     case FF_PROFILE_UNKNOWN:
225         ctx->va_profile = VAProfileVP9Profile0;
226         ctx->va_rt_format = VA_RT_FORMAT_YUV420;
227         break;
228     case FF_PROFILE_VP9_1:
229         av_log(avctx, AV_LOG_ERROR, "VP9 profile 1 is not "
230                "supported.\n");
231         return AVERROR_PATCHWELCOME;
232     case FF_PROFILE_VP9_2:
233         ctx->va_profile = VAProfileVP9Profile2;
234         ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP;
235         break;
236     case FF_PROFILE_VP9_3:
237         av_log(avctx, AV_LOG_ERROR, "VP9 profile 3 is not "
238                "supported.\n");
239         return AVERROR_PATCHWELCOME;
240     default:
241         av_log(avctx, AV_LOG_ERROR, "Unknown VP9 profile %d.\n",
242                avctx->profile);
243         return AVERROR(EINVAL);
244     }
245     ctx->va_entrypoint = VAEntrypointEncSlice;
246
247     if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
248         ctx->va_rc_mode = VA_RC_CQP;
249     } else if (avctx->bit_rate > 0) {
250         if (avctx->bit_rate == avctx->rc_max_rate)
251             ctx->va_rc_mode = VA_RC_CBR;
252         else
253             ctx->va_rc_mode = VA_RC_VBR;
254     } else {
255         ctx->va_rc_mode = VA_RC_CQP;
256     }
257
258     // Packed headers are not currently supported.
259     ctx->va_packed_headers = 0;
260
261     // Surfaces must be aligned to superblock boundaries.
262     ctx->surface_width  = FFALIGN(avctx->width,  64);
263     ctx->surface_height = FFALIGN(avctx->height, 64);
264
265     return ff_vaapi_encode_init(avctx);
266 }
267
268 #define OFFSET(x) offsetof(VAAPIEncodeVP9Context, x)
269 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
270 static const AVOption vaapi_encode_vp9_options[] = {
271     { "loop_filter_level", "Loop filter level",
272       OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS },
273     { "loop_filter_sharpness", "Loop filter sharpness",
274       OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, FLAGS },
275     { NULL },
276 };
277
278 static const AVCodecDefault vaapi_encode_vp9_defaults[] = {
279     { "profile",        "0"   },
280     { "b",              "0"   },
281     { "bf",             "0"   },
282     { "g",              "250" },
283     { "global_quality", "100" },
284     { NULL },
285 };
286
287 static const AVClass vaapi_encode_vp9_class = {
288     .class_name = "vp9_vaapi",
289     .item_name  = av_default_item_name,
290     .option     = vaapi_encode_vp9_options,
291     .version    = LIBAVUTIL_VERSION_INT,
292 };
293
294 AVCodec ff_vp9_vaapi_encoder = {
295     .name           = "vp9_vaapi",
296     .long_name      = NULL_IF_CONFIG_SMALL("VP9 (VAAPI)"),
297     .type           = AVMEDIA_TYPE_VIDEO,
298     .id             = AV_CODEC_ID_VP9,
299     .priv_data_size = sizeof(VAAPIEncodeVP9Context),
300     .init           = &vaapi_encode_vp9_init,
301     .encode2        = &ff_vaapi_encode2,
302     .close          = &ff_vaapi_encode_close,
303     .priv_class     = &vaapi_encode_vp9_class,
304     .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
305     .defaults       = vaapi_encode_vp9_defaults,
306     .pix_fmts = (const enum AVPixelFormat[]) {
307         AV_PIX_FMT_VAAPI,
308         AV_PIX_FMT_NONE,
309     },
310     .wrapper_name   = "vaapi",
311 };