]> git.sesse.net Git - ffmpeg/blob - libavcodec/vaapi_encode_vp9.c
avcodec: add metadata to identify wrappers and hardware decoders
[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     int q_idx_idr;
37     int q_idx_p;
38     int q_idx_b;
39
40     // Reference direction for B-like frames:
41     // 0 - most recent P/IDR frame is last.
42     // 1 - most recent P frame is golden.
43     int last_ref_dir;
44 } VAAPIEncodeVP9Context;
45
46 typedef struct VAAPIEncodeVP9Options {
47     int loop_filter_level;
48     int loop_filter_sharpness;
49 } VAAPIEncodeVP9Options;
50
51
52 #define vseq_var(name)     vseq->name, name
53 #define vseq_field(name)   vseq->seq_fields.bits.name, name
54 #define vpic_var(name)     vpic->name, name
55 #define vpic_field(name)   vpic->pic_fields.bits.name, name
56
57
58 static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx)
59 {
60     VAAPIEncodeContext               *ctx = avctx->priv_data;
61     VAEncSequenceParameterBufferVP9 *vseq = ctx->codec_sequence_params;
62     VAEncPictureParameterBufferVP9  *vpic = ctx->codec_picture_params;
63
64     vseq->max_frame_width  = avctx->width;
65     vseq->max_frame_height = avctx->height;
66
67     vseq->kf_auto = 0;
68
69     if (!(ctx->va_rc_mode & VA_RC_CQP)) {
70         vseq->bits_per_second = avctx->bit_rate;
71         vseq->intra_period    = avctx->gop_size;
72     }
73
74     vpic->frame_width_src  = avctx->width;
75     vpic->frame_height_src = avctx->height;
76     vpic->frame_width_dst  = avctx->width;
77     vpic->frame_height_dst = avctx->height;
78
79     return 0;
80 }
81
82 static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
83                                                 VAAPIEncodePicture *pic)
84 {
85     VAAPIEncodeContext              *ctx = avctx->priv_data;
86     VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params;
87     VAAPIEncodeVP9Context          *priv = ctx->priv_data;
88     VAAPIEncodeVP9Options           *opt = ctx->codec_options;
89     int i;
90
91     vpic->reconstructed_frame = pic->recon_surface;
92     vpic->coded_buf = pic->output_buffer;
93
94     switch (pic->type) {
95     case PICTURE_TYPE_IDR:
96         av_assert0(pic->nb_refs == 0);
97         vpic->ref_flags.bits.force_kf = 1;
98         vpic->refresh_frame_flags = 0x01;
99         priv->last_ref_dir = 0;
100         break;
101     case PICTURE_TYPE_P:
102         av_assert0(pic->nb_refs == 1);
103         if (avctx->max_b_frames > 0) {
104             if (priv->last_ref_dir) {
105                 vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
106                 vpic->ref_flags.bits.ref_gf_idx         = 1;
107                 vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
108                 vpic->refresh_frame_flags = 0x01;
109             } else {
110                 vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
111                 vpic->ref_flags.bits.ref_last_idx       = 0;
112                 vpic->ref_flags.bits.ref_last_sign_bias = 1;
113                 vpic->refresh_frame_flags = 0x02;
114             }
115         } else {
116             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
117             vpic->ref_flags.bits.ref_last_idx       = 0;
118             vpic->ref_flags.bits.ref_last_sign_bias = 1;
119             vpic->refresh_frame_flags = 0x01;
120         }
121         break;
122     case PICTURE_TYPE_B:
123         av_assert0(pic->nb_refs == 2);
124         if (priv->last_ref_dir) {
125             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
126             vpic->ref_flags.bits.ref_frame_ctrl_l1  = 2;
127             vpic->ref_flags.bits.ref_last_idx       = 0;
128             vpic->ref_flags.bits.ref_last_sign_bias = 1;
129             vpic->ref_flags.bits.ref_gf_idx         = 1;
130             vpic->ref_flags.bits.ref_gf_sign_bias   = 0;
131         } else {
132             vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
133             vpic->ref_flags.bits.ref_frame_ctrl_l1  = 1;
134             vpic->ref_flags.bits.ref_last_idx       = 0;
135             vpic->ref_flags.bits.ref_last_sign_bias = 0;
136             vpic->ref_flags.bits.ref_gf_idx         = 1;
137             vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
138         }
139         vpic->refresh_frame_flags = 0x00;
140         break;
141     default:
142         av_assert0(0 && "invalid picture type");
143     }
144
145     for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
146         vpic->reference_frames[i] = VA_INVALID_SURFACE;
147     if (pic->type == PICTURE_TYPE_P) {
148         av_assert0(pic->refs[0]);
149         vpic->reference_frames[priv->last_ref_dir] =
150             pic->refs[0]->recon_surface;
151     } else if (pic->type == PICTURE_TYPE_B) {
152         av_assert0(pic->refs[0] && pic->refs[1]);
153         vpic->reference_frames[!priv->last_ref_dir] =
154             pic->refs[0]->recon_surface;
155         vpic->reference_frames[priv->last_ref_dir] =
156             pic->refs[1]->recon_surface;
157     }
158
159     vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR);
160     vpic->pic_flags.bits.show_frame = pic->display_order <= pic->encode_order;
161
162     if (pic->type == PICTURE_TYPE_IDR)
163         vpic->luma_ac_qindex     = priv->q_idx_idr;
164     else if (pic->type == PICTURE_TYPE_P)
165         vpic->luma_ac_qindex     = priv->q_idx_p;
166     else
167         vpic->luma_ac_qindex     = priv->q_idx_b;
168     vpic->luma_dc_qindex_delta   = 0;
169     vpic->chroma_ac_qindex_delta = 0;
170     vpic->chroma_dc_qindex_delta = 0;
171
172     vpic->filter_level    = opt->loop_filter_level;
173     vpic->sharpness_level = opt->loop_filter_sharpness;
174
175     if (avctx->max_b_frames > 0 && pic->type == PICTURE_TYPE_P)
176         priv->last_ref_dir = !priv->last_ref_dir;
177
178     return 0;
179 }
180
181 static av_cold int vaapi_encode_vp9_configure(AVCodecContext *avctx)
182 {
183     VAAPIEncodeContext     *ctx = avctx->priv_data;
184     VAAPIEncodeVP9Context *priv = ctx->priv_data;
185
186     priv->q_idx_p = av_clip(avctx->global_quality, 0, VP9_MAX_QUANT);
187     if (avctx->i_quant_factor > 0.0)
188         priv->q_idx_idr = av_clip((avctx->global_quality *
189                                    avctx->i_quant_factor +
190                                    avctx->i_quant_offset) + 0.5,
191                                   0, VP9_MAX_QUANT);
192     else
193         priv->q_idx_idr = priv->q_idx_p;
194     if (avctx->b_quant_factor > 0.0)
195         priv->q_idx_b = av_clip((avctx->global_quality *
196                                  avctx->b_quant_factor +
197                                  avctx->b_quant_offset) + 0.5,
198                                 0, VP9_MAX_QUANT);
199     else
200         priv->q_idx_b = priv->q_idx_p;
201
202     return 0;
203 }
204
205 static const VAAPIEncodeType vaapi_encode_type_vp9 = {
206     .configure             = &vaapi_encode_vp9_configure,
207
208     .priv_data_size        = sizeof(VAAPIEncodeVP9Context),
209
210     .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP9),
211     .init_sequence_params  = &vaapi_encode_vp9_init_sequence_params,
212
213     .picture_params_size   = sizeof(VAEncPictureParameterBufferVP9),
214     .init_picture_params   = &vaapi_encode_vp9_init_picture_params,
215 };
216
217 static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx)
218 {
219     VAAPIEncodeContext *ctx = avctx->priv_data;
220
221     ctx->codec = &vaapi_encode_type_vp9;
222
223     switch (avctx->profile) {
224     case FF_PROFILE_VP9_0:
225     case FF_PROFILE_UNKNOWN:
226         ctx->va_profile = VAProfileVP9Profile0;
227         ctx->va_rt_format = VA_RT_FORMAT_YUV420;
228         break;
229     case FF_PROFILE_VP9_1:
230         av_log(avctx, AV_LOG_ERROR, "VP9 profile 1 is not "
231                "supported.\n");
232         return AVERROR_PATCHWELCOME;
233     case FF_PROFILE_VP9_2:
234         ctx->va_profile = VAProfileVP9Profile2;
235         ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP;
236         break;
237     case FF_PROFILE_VP9_3:
238         av_log(avctx, AV_LOG_ERROR, "VP9 profile 3 is not "
239                "supported.\n");
240         return AVERROR_PATCHWELCOME;
241     default:
242         av_log(avctx, AV_LOG_ERROR, "Unknown VP9 profile %d.\n",
243                avctx->profile);
244         return AVERROR(EINVAL);
245     }
246     ctx->va_entrypoint = VAEntrypointEncSlice;
247
248     if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
249         ctx->va_rc_mode = VA_RC_CQP;
250     } else if (avctx->bit_rate > 0) {
251         if (avctx->bit_rate == avctx->rc_max_rate)
252             ctx->va_rc_mode = VA_RC_CBR;
253         else
254             ctx->va_rc_mode = VA_RC_VBR;
255     } else {
256         ctx->va_rc_mode = VA_RC_CQP;
257     }
258
259     // Packed headers are not currently supported.
260     ctx->va_packed_headers = 0;
261
262     // Surfaces must be aligned to superblock boundaries.
263     ctx->surface_width  = FFALIGN(avctx->width,  64);
264     ctx->surface_height = FFALIGN(avctx->height, 64);
265
266     return ff_vaapi_encode_init(avctx);
267 }
268
269 #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \
270                    offsetof(VAAPIEncodeVP9Options, x))
271 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
272 static const AVOption vaapi_encode_vp9_options[] = {
273     { "loop_filter_level", "Loop filter level",
274       OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS },
275     { "loop_filter_sharpness", "Loop filter sharpness",
276       OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, FLAGS },
277     { NULL },
278 };
279
280 static const AVCodecDefault vaapi_encode_vp9_defaults[] = {
281     { "profile",        "0"   },
282     { "b",              "0"   },
283     { "bf",             "0"   },
284     { "g",              "250" },
285     { "global_quality", "100" },
286     { NULL },
287 };
288
289 static const AVClass vaapi_encode_vp9_class = {
290     .class_name = "vp9_vaapi",
291     .item_name  = av_default_item_name,
292     .option     = vaapi_encode_vp9_options,
293     .version    = LIBAVUTIL_VERSION_INT,
294 };
295
296 AVCodec ff_vp9_vaapi_encoder = {
297     .name           = "vp9_vaapi",
298     .long_name      = NULL_IF_CONFIG_SMALL("VP9 (VAAPI)"),
299     .type           = AVMEDIA_TYPE_VIDEO,
300     .id             = AV_CODEC_ID_VP9,
301     .priv_data_size = (sizeof(VAAPIEncodeContext) +
302                        sizeof(VAAPIEncodeVP9Options)),
303     .init           = &vaapi_encode_vp9_init,
304     .encode2        = &ff_vaapi_encode2,
305     .close          = &ff_vaapi_encode_close,
306     .priv_class     = &vaapi_encode_vp9_class,
307     .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
308     .defaults       = vaapi_encode_vp9_defaults,
309     .pix_fmts = (const enum AVPixelFormat[]) {
310         AV_PIX_FMT_VAAPI,
311         AV_PIX_FMT_NONE,
312     },
313     .wrapper_name   = "vaapi",
314 };