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_vp8.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 "codec_internal.h" 30#include "vaapi_encode.h" 31#include "vp8.h" 32 33 34typedef struct VAAPIEncodeVP8Context { 35 VAAPIEncodeContext common; 36 37 // User options. 38 int loop_filter_level; 39 int loop_filter_sharpness; 40 41 // Derived settings. 42 int q_index_i; 43 int q_index_p; 44} VAAPIEncodeVP8Context; 45 46 47#define vseq_var(name) vseq->name, name 48#define vseq_field(name) vseq->seq_fields.bits.name, name 49#define vpic_var(name) vpic->name, name 50#define vpic_field(name) vpic->pic_fields.bits.name, name 51 52 53static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx) 54{ 55 VAAPIEncodeContext *ctx = avctx->priv_data; 56 VAEncSequenceParameterBufferVP8 *vseq = ctx->codec_sequence_params; 57 58 vseq->frame_width = avctx->width; 59 vseq->frame_height = avctx->height; 60 61 vseq->frame_width_scale = 0; 62 vseq->frame_height_scale = 0; 63 64 vseq->error_resilient = 0; 65 vseq->kf_auto = 0; 66 67 if (!(ctx->va_rc_mode & VA_RC_CQP)) { 68 vseq->bits_per_second = ctx->va_bit_rate; 69 vseq->intra_period = ctx->gop_size; 70 } 71 72 return 0; 73} 74 75static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, 76 VAAPIEncodePicture *pic) 77{ 78 VAAPIEncodeVP8Context *priv = avctx->priv_data; 79 VAEncPictureParameterBufferVP8 *vpic = pic->codec_picture_params; 80 int i; 81 82 vpic->reconstructed_frame = pic->recon_surface; 83 84 vpic->coded_buf = pic->output_buffer; 85 86 switch (pic->type) { 87 case PICTURE_TYPE_IDR: 88 case PICTURE_TYPE_I: 89 av_assert0(pic->nb_refs == 0); 90 vpic->ref_flags.bits.force_kf = 1; 91 vpic->ref_last_frame = 92 vpic->ref_gf_frame = 93 vpic->ref_arf_frame = 94 VA_INVALID_SURFACE; 95 break; 96 case PICTURE_TYPE_P: 97 av_assert0(pic->nb_refs == 1); 98 vpic->ref_flags.bits.no_ref_last = 0; 99 vpic->ref_flags.bits.no_ref_gf = 1; 100 vpic->ref_flags.bits.no_ref_arf = 1; 101 vpic->ref_last_frame = 102 vpic->ref_gf_frame = 103 vpic->ref_arf_frame = 104 pic->refs[0]->recon_surface; 105 break; 106 default: 107 av_assert0(0 && "invalid picture type"); 108 } 109 110 vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR); 111 vpic->pic_flags.bits.show_frame = 1; 112 113 vpic->pic_flags.bits.refresh_last = 1; 114 vpic->pic_flags.bits.refresh_golden_frame = 1; 115 vpic->pic_flags.bits.refresh_alternate_frame = 1; 116 117 vpic->pic_flags.bits.version = 0; 118 vpic->pic_flags.bits.loop_filter_type = 0; 119 for (i = 0; i < 4; i++) 120 vpic->loop_filter_level[i] = priv->loop_filter_level; 121 vpic->sharpness_level = priv->loop_filter_sharpness; 122 123 vpic->clamp_qindex_low = 0; 124 vpic->clamp_qindex_high = 127; 125 126 return 0; 127} 128 129static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx, 130 VAAPIEncodePicture *pic, 131 int index, int *type, 132 char *data, size_t *data_len) 133{ 134 VAAPIEncodeVP8Context *priv = avctx->priv_data; 135 VAQMatrixBufferVP8 quant; 136 int i, q; 137 138 if (index > 0) 139 return AVERROR_EOF; 140 141 if (*data_len < sizeof(quant)) 142 return AVERROR(EINVAL); 143 *type = VAQMatrixBufferType; 144 *data_len = sizeof(quant); 145 146 memset(&quant, 0, sizeof(quant)); 147 148 if (pic->type == PICTURE_TYPE_P) 149 q = priv->q_index_p; 150 else 151 q = priv->q_index_i; 152 153 for (i = 0; i < 4; i++) 154 quant.quantization_index[i] = q; 155 for (i = 0; i < 5; i++) 156 quant.quantization_index_delta[i] = 0; 157 158 memcpy(data, &quant, sizeof(quant)); 159 return 0; 160} 161 162static av_cold int vaapi_encode_vp8_configure(AVCodecContext *avctx) 163{ 164 VAAPIEncodeContext *ctx = avctx->priv_data; 165 VAAPIEncodeVP8Context *priv = avctx->priv_data; 166 167 priv->q_index_p = av_clip(ctx->rc_quality, 0, VP8_MAX_QUANT); 168 if (avctx->i_quant_factor > 0.0) 169 priv->q_index_i = 170 av_clip((avctx->i_quant_factor * priv->q_index_p + 171 avctx->i_quant_offset) + 0.5, 172 0, VP8_MAX_QUANT); 173 else 174 priv->q_index_i = priv->q_index_p; 175 176 ctx->roi_quant_range = VP8_MAX_QUANT; 177 178 return 0; 179} 180 181static const VAAPIEncodeProfile vaapi_encode_vp8_profiles[] = { 182 { 0 /* VP8 has no profiles */, 8, 3, 1, 1, VAProfileVP8Version0_3 }, 183 { FF_PROFILE_UNKNOWN } 184}; 185 186static const VAAPIEncodeType vaapi_encode_type_vp8 = { 187 .profiles = vaapi_encode_vp8_profiles, 188 189 .configure = &vaapi_encode_vp8_configure, 190 191 .default_quality = 40, 192 193 .sequence_params_size = sizeof(VAEncSequenceParameterBufferVP8), 194 .init_sequence_params = &vaapi_encode_vp8_init_sequence_params, 195 196 .picture_params_size = sizeof(VAEncPictureParameterBufferVP8), 197 .init_picture_params = &vaapi_encode_vp8_init_picture_params, 198 199 .write_extra_buffer = &vaapi_encode_vp8_write_quant_table, 200}; 201 202static av_cold int vaapi_encode_vp8_init(AVCodecContext *avctx) 203{ 204 VAAPIEncodeContext *ctx = avctx->priv_data; 205 206 ctx->codec = &vaapi_encode_type_vp8; 207 208 // No packed headers are currently desired. VP8 has no metadata 209 // which would be useful to write, and no existing driver supports 210 // adding them anyway. 211 ctx->desired_packed_headers = 0; 212 213 return ff_vaapi_encode_init(avctx); 214} 215 216#define OFFSET(x) offsetof(VAAPIEncodeVP8Context, x) 217#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) 218static const AVOption vaapi_encode_vp8_options[] = { 219 VAAPI_ENCODE_COMMON_OPTIONS, 220 VAAPI_ENCODE_RC_OPTIONS, 221 222 { "loop_filter_level", "Loop filter level", 223 OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS }, 224 { "loop_filter_sharpness", "Loop filter sharpness", 225 OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, FLAGS }, 226 { NULL }, 227}; 228 229static const FFCodecDefault vaapi_encode_vp8_defaults[] = { 230 { "b", "0" }, 231 { "bf", "0" }, 232 { "g", "120" }, 233 { "qmin", "-1" }, 234 { "qmax", "-1" }, 235 { NULL }, 236}; 237 238static const AVClass vaapi_encode_vp8_class = { 239 .class_name = "vp8_vaapi", 240 .item_name = av_default_item_name, 241 .option = vaapi_encode_vp8_options, 242 .version = LIBAVUTIL_VERSION_INT, 243}; 244 245const FFCodec ff_vp8_vaapi_encoder = { 246 .p.name = "vp8_vaapi", 247 .p.long_name = NULL_IF_CONFIG_SMALL("VP8 (VAAPI)"), 248 .p.type = AVMEDIA_TYPE_VIDEO, 249 .p.id = AV_CODEC_ID_VP8, 250 .priv_data_size = sizeof(VAAPIEncodeVP8Context), 251 .init = &vaapi_encode_vp8_init, 252 FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet), 253 .close = &ff_vaapi_encode_close, 254 .p.priv_class = &vaapi_encode_vp8_class, 255 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | 256 AV_CODEC_CAP_DR1, 257 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, 258 .defaults = vaapi_encode_vp8_defaults, 259 .p.pix_fmts = (const enum AVPixelFormat[]) { 260 AV_PIX_FMT_VAAPI, 261 AV_PIX_FMT_NONE, 262 }, 263 .hw_configs = ff_vaapi_encode_hw_configs, 264 .p.wrapper_name = "vaapi", 265}; 266