Browse code

vaapi_encode: Add VP9 support

(cherry picked from commit 0fd91e4bfc00a6609b59d1ce3a9f152184e62601)

Mark Thompson authored on 2016/11/29 08:54:57
Showing 5 changed files
... ...
@@ -2797,6 +2797,8 @@ vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8"
2797 2797
 vp8_vaapi_encoder_select="vaapi_encode"
2798 2798
 vp9_cuvid_decoder_deps="cuda cuvid"
2799 2799
 vp9_mediacodec_decoder_deps="mediacodec"
2800
+vp9_vaapi_encoder_deps="VAEncPictureParameterBufferVP9"
2801
+vp9_vaapi_encoder_select="vaapi_encode"
2800 2802
 wmv3_crystalhd_decoder_select="crystalhd"
2801 2803
 wmv3_vdpau_decoder_select="vc1_vdpau_decoder"
2802 2804
 
... ...
@@ -5725,6 +5727,7 @@ check_type "va/va.h va/va_enc_hevc.h" "VAEncPictureParameterBufferHEVC"
5725 5725
 check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG"
5726 5726
 check_type "va/va.h va/va_enc_mpeg2.h" "VAEncPictureParameterBufferMPEG2"
5727 5727
 check_type "va/va.h va/va_enc_vp8.h"  "VAEncPictureParameterBufferVP8"
5728
+check_type "va/va.h va/va_enc_vp9.h"  "VAEncPictureParameterBufferVP9"
5728 5729
 
5729 5730
 check_type "vdpau/vdpau.h" "VdpPictureInfoHEVC"
5730 5731
 
... ...
@@ -627,6 +627,7 @@ OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r
627 627
                                           vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o
628 628
 OBJS-$(CONFIG_VP9_CUVID_DECODER)       += cuvid.o
629 629
 OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER)  += mediacodecdec.o
630
+OBJS-$(CONFIG_VP9_VAAPI_ENCODER)       += vaapi_encode_vp9.o
630 631
 OBJS-$(CONFIG_VPLAYER_DECODER)         += textdec.o ass.o
631 632
 OBJS-$(CONFIG_VQA_DECODER)             += vqavideo.o
632 633
 OBJS-$(CONFIG_WAVPACK_DECODER)         += wavpack.o
... ...
@@ -680,6 +680,7 @@ static void register_all(void)
680 680
     REGISTER_ENCODER(VP8_VAAPI,         vp8_vaapi);
681 681
     REGISTER_DECODER(VP9_CUVID,         vp9_cuvid);
682 682
     REGISTER_DECODER(VP9_MEDIACODEC,    vp9_mediacodec);
683
+    REGISTER_ENCODER(VP9_VAAPI,         vp9_vaapi);
683 684
 
684 685
     /* parsers */
685 686
     REGISTER_PARSER(AAC,                aac);
686 687
new file mode 100644
... ...
@@ -0,0 +1,313 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include <va/va.h>
19
+#include <va/va_enc_vp9.h>
20
+
21
+#include "libavutil/avassert.h"
22
+#include "libavutil/common.h"
23
+#include "libavutil/internal.h"
24
+#include "libavutil/opt.h"
25
+#include "libavutil/pixfmt.h"
26
+
27
+#include "avcodec.h"
28
+#include "internal.h"
29
+#include "vaapi_encode.h"
30
+
31
+#define VP9_MAX_QUANT 255
32
+
33
+
34
+typedef struct VAAPIEncodeVP9Context {
35
+    int q_idx_idr;
36
+    int q_idx_p;
37
+    int q_idx_b;
38
+
39
+    // Reference direction for B-like frames:
40
+    // 0 - most recent P/IDR frame is last.
41
+    // 1 - most recent P frame is golden.
42
+    int last_ref_dir;
43
+} VAAPIEncodeVP9Context;
44
+
45
+typedef struct VAAPIEncodeVP9Options {
46
+    int loop_filter_level;
47
+    int loop_filter_sharpness;
48
+} VAAPIEncodeVP9Options;
49
+
50
+
51
+#define vseq_var(name)     vseq->name, name
52
+#define vseq_field(name)   vseq->seq_fields.bits.name, name
53
+#define vpic_var(name)     vpic->name, name
54
+#define vpic_field(name)   vpic->pic_fields.bits.name, name
55
+
56
+
57
+static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx)
58
+{
59
+    VAAPIEncodeContext               *ctx = avctx->priv_data;
60
+    VAEncSequenceParameterBufferVP9 *vseq = ctx->codec_sequence_params;
61
+    VAEncPictureParameterBufferVP9  *vpic = ctx->codec_picture_params;
62
+
63
+    vseq->max_frame_width  = avctx->width;
64
+    vseq->max_frame_height = avctx->height;
65
+
66
+    vseq->kf_auto = 0;
67
+
68
+    if (!(ctx->va_rc_mode & VA_RC_CQP)) {
69
+        vseq->bits_per_second = avctx->bit_rate;
70
+        vseq->intra_period    = avctx->gop_size;
71
+    }
72
+
73
+    vpic->frame_width_src  = avctx->width;
74
+    vpic->frame_height_src = avctx->height;
75
+    vpic->frame_width_dst  = avctx->width;
76
+    vpic->frame_height_dst = avctx->height;
77
+
78
+    return 0;
79
+}
80
+
81
+static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
82
+                                                VAAPIEncodePicture *pic)
83
+{
84
+    VAAPIEncodeContext              *ctx = avctx->priv_data;
85
+    VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params;
86
+    VAAPIEncodeVP9Context          *priv = ctx->priv_data;
87
+    VAAPIEncodeVP9Options           *opt = ctx->codec_options;
88
+    int i;
89
+
90
+    vpic->reconstructed_frame = pic->recon_surface;
91
+    vpic->coded_buf = pic->output_buffer;
92
+
93
+    switch (pic->type) {
94
+    case PICTURE_TYPE_IDR:
95
+        av_assert0(pic->nb_refs == 0);
96
+        vpic->ref_flags.bits.force_kf = 1;
97
+        vpic->refresh_frame_flags = 0x01;
98
+        priv->last_ref_dir = 0;
99
+        break;
100
+    case PICTURE_TYPE_P:
101
+        av_assert0(pic->nb_refs == 1);
102
+        if (avctx->max_b_frames > 0) {
103
+            if (priv->last_ref_dir) {
104
+                vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
105
+                vpic->ref_flags.bits.ref_gf_idx         = 1;
106
+                vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
107
+                vpic->refresh_frame_flags = 0x01;
108
+            } else {
109
+                vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
110
+                vpic->ref_flags.bits.ref_last_idx       = 0;
111
+                vpic->ref_flags.bits.ref_last_sign_bias = 1;
112
+                vpic->refresh_frame_flags = 0x02;
113
+            }
114
+        } else {
115
+            vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
116
+            vpic->ref_flags.bits.ref_last_idx       = 0;
117
+            vpic->ref_flags.bits.ref_last_sign_bias = 1;
118
+            vpic->refresh_frame_flags = 0x01;
119
+        }
120
+        break;
121
+    case PICTURE_TYPE_B:
122
+        av_assert0(pic->nb_refs == 2);
123
+        if (priv->last_ref_dir) {
124
+            vpic->ref_flags.bits.ref_frame_ctrl_l0  = 1;
125
+            vpic->ref_flags.bits.ref_frame_ctrl_l1  = 2;
126
+            vpic->ref_flags.bits.ref_last_idx       = 0;
127
+            vpic->ref_flags.bits.ref_last_sign_bias = 1;
128
+            vpic->ref_flags.bits.ref_gf_idx         = 1;
129
+            vpic->ref_flags.bits.ref_gf_sign_bias   = 0;
130
+        } else {
131
+            vpic->ref_flags.bits.ref_frame_ctrl_l0  = 2;
132
+            vpic->ref_flags.bits.ref_frame_ctrl_l1  = 1;
133
+            vpic->ref_flags.bits.ref_last_idx       = 0;
134
+            vpic->ref_flags.bits.ref_last_sign_bias = 0;
135
+            vpic->ref_flags.bits.ref_gf_idx         = 1;
136
+            vpic->ref_flags.bits.ref_gf_sign_bias   = 1;
137
+        }
138
+        vpic->refresh_frame_flags = 0x00;
139
+        break;
140
+    default:
141
+        av_assert0(0 && "invalid picture type");
142
+    }
143
+
144
+    for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
145
+        vpic->reference_frames[i] = VA_INVALID_SURFACE;
146
+    if (pic->type == PICTURE_TYPE_P) {
147
+        av_assert0(pic->refs[0]);
148
+        vpic->reference_frames[priv->last_ref_dir] =
149
+            pic->refs[0]->recon_surface;
150
+    } else if (pic->type == PICTURE_TYPE_B) {
151
+        av_assert0(pic->refs[0] && pic->refs[1]);
152
+        vpic->reference_frames[!priv->last_ref_dir] =
153
+            pic->refs[0]->recon_surface;
154
+        vpic->reference_frames[priv->last_ref_dir] =
155
+            pic->refs[1]->recon_surface;
156
+    }
157
+
158
+    vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR);
159
+    vpic->pic_flags.bits.show_frame = pic->display_order <= pic->encode_order;
160
+
161
+    if (pic->type == PICTURE_TYPE_IDR)
162
+        vpic->luma_ac_qindex     = priv->q_idx_idr;
163
+    else if (pic->type == PICTURE_TYPE_P)
164
+        vpic->luma_ac_qindex     = priv->q_idx_p;
165
+    else
166
+        vpic->luma_ac_qindex     = priv->q_idx_b;
167
+    vpic->luma_dc_qindex_delta   = 0;
168
+    vpic->chroma_ac_qindex_delta = 0;
169
+    vpic->chroma_dc_qindex_delta = 0;
170
+
171
+    vpic->filter_level    = opt->loop_filter_level;
172
+    vpic->sharpness_level = opt->loop_filter_sharpness;
173
+
174
+    if (avctx->max_b_frames > 0 && pic->type == PICTURE_TYPE_P)
175
+        priv->last_ref_dir = !priv->last_ref_dir;
176
+
177
+    return 0;
178
+}
179
+
180
+static av_cold int vaapi_encode_vp9_configure(AVCodecContext *avctx)
181
+{
182
+    VAAPIEncodeContext     *ctx = avctx->priv_data;
183
+    VAAPIEncodeVP9Context *priv = ctx->priv_data;
184
+
185
+    priv->q_idx_p = av_clip(avctx->global_quality, 0, VP9_MAX_QUANT);
186
+    if (avctx->i_quant_factor > 0.0)
187
+        priv->q_idx_idr = av_clip((avctx->global_quality *
188
+                                   avctx->i_quant_factor +
189
+                                   avctx->i_quant_offset) + 0.5,
190
+                                  0, VP9_MAX_QUANT);
191
+    else
192
+        priv->q_idx_idr = priv->q_idx_p;
193
+    if (avctx->b_quant_factor > 0.0)
194
+        priv->q_idx_b = av_clip((avctx->global_quality *
195
+                                 avctx->b_quant_factor +
196
+                                 avctx->b_quant_offset) + 0.5,
197
+                                0, VP9_MAX_QUANT);
198
+    else
199
+        priv->q_idx_b = priv->q_idx_p;
200
+
201
+    return 0;
202
+}
203
+
204
+static const VAAPIEncodeType vaapi_encode_type_vp9 = {
205
+    .configure             = &vaapi_encode_vp9_configure,
206
+
207
+    .priv_data_size        = sizeof(VAAPIEncodeVP9Context),
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(VAAPIEncodeContext, codec_options_data) + \
269
+                   offsetof(VAAPIEncodeVP9Options, x))
270
+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
271
+static const AVOption vaapi_encode_vp9_options[] = {
272
+    { "loop_filter_level", "Loop filter level",
273
+      OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS },
274
+    { "loop_filter_sharpness", "Loop filter sharpness",
275
+      OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, FLAGS },
276
+    { NULL },
277
+};
278
+
279
+static const AVCodecDefault vaapi_encode_vp9_defaults[] = {
280
+    { "profile",        "0"   },
281
+    { "b",              "0"   },
282
+    { "bf",             "0"   },
283
+    { "g",              "250" },
284
+    { "global_quality", "100" },
285
+    { NULL },
286
+};
287
+
288
+static const AVClass vaapi_encode_vp9_class = {
289
+    .class_name = "vp9_vaapi",
290
+    .item_name  = av_default_item_name,
291
+    .option     = vaapi_encode_vp9_options,
292
+    .version    = LIBAVUTIL_VERSION_INT,
293
+};
294
+
295
+AVCodec ff_vp9_vaapi_encoder = {
296
+    .name           = "vp9_vaapi",
297
+    .long_name      = NULL_IF_CONFIG_SMALL("VP9 (VAAPI)"),
298
+    .type           = AVMEDIA_TYPE_VIDEO,
299
+    .id             = AV_CODEC_ID_VP9,
300
+    .priv_data_size = (sizeof(VAAPIEncodeContext) +
301
+                       sizeof(VAAPIEncodeVP9Options)),
302
+    .init           = &vaapi_encode_vp9_init,
303
+    .encode2        = &ff_vaapi_encode2,
304
+    .close          = &ff_vaapi_encode_close,
305
+    .priv_class     = &vaapi_encode_vp9_class,
306
+    .capabilities   = AV_CODEC_CAP_DELAY,
307
+    .defaults       = vaapi_encode_vp9_defaults,
308
+    .pix_fmts = (const enum AVPixelFormat[]) {
309
+        AV_PIX_FMT_VAAPI,
310
+        AV_PIX_FMT_NONE,
311
+    },
312
+};
... ...
@@ -29,7 +29,7 @@
29 29
 
30 30
 #define LIBAVCODEC_VERSION_MAJOR  57
31 31
 #define LIBAVCODEC_VERSION_MINOR  99
32
-#define LIBAVCODEC_VERSION_MICRO 101
32
+#define LIBAVCODEC_VERSION_MICRO 102
33 33
 
34 34
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
35 35
                                                LIBAVCODEC_VERSION_MINOR, \