---
I was avoiding this one until I could do VP9 at the same time because the 
headers and probability stuff looked nasty.  Turns out that was entirely 
unfounded, because the i965 driver doesn't actually support any of those 
things, and therefore it's pretty much trivial if we only support P frames.  
(That does also mean that the result is atrocious, so this is mainly a 
curiosity for now.)


 configure                     |   3 +
 libavcodec/Makefile           |   1 +
 libavcodec/allcodecs.c        |   1 +
 libavcodec/vaapi_encode_vp8.c | 261 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 266 insertions(+)
 create mode 100644 libavcodec/vaapi_encode_vp8.c

diff --git a/configure b/configure
index ab95063..2ef5a28 100755
--- a/configure
+++ b/configure
@@ -2231,6 +2231,8 @@ vc1_qsv_decoder_deps="libmfx"
 vc1_qsv_decoder_select="qsvdec vc1_qsv_hwaccel vc1_parser"
 vp8_qsv_decoder_deps="libmfx"
 vp8_qsv_decoder_select="qsvdec vp8_qsv_hwaccel vp8_parser"
+vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8"
+vp8_vaapi_encoder_select="vaapi_encode"
 vp9_vaapi_encoder_deps="VAEncPictureParameterBufferVP9"
 vp9_vaapi_encoder_select="vaapi_encode"
 
@@ -4582,6 +4584,7 @@ check_type "va/va.h va/va_vpp.h" 
"VAProcPipelineParameterBuffer"
 check_type "va/va.h va/va_enc_h264.h" "VAEncPictureParameterBufferH264"
 check_type "va/va.h va/va_enc_hevc.h" "VAEncPictureParameterBufferHEVC"
 check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG"
+check_type "va/va.h va/va_enc_vp8.h"  "VAEncPictureParameterBufferVP8"
 check_type "va/va.h va/va_enc_vp9.h"  "VAEncPictureParameterBufferVP9"
 
 check_type "vdpau/vdpau.h" "VdpPictureInfoHEVC"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 334273c..27c2825 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -477,6 +477,7 @@ OBJS-$(CONFIG_VP6_DECODER)             += vp6.o vp56.o 
vp56data.o \
 OBJS-$(CONFIG_VP7_DECODER)             += vp8.o vp56rac.o
 OBJS-$(CONFIG_VP8_DECODER)             += vp8.o vp56rac.o
 OBJS-$(CONFIG_VP8_QSV_DECODER)         += qsvdec_other.o
+OBJS-$(CONFIG_VP8_VAAPI_ENCODER)       += vaapi_encode_vp8.o
 OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o \
                                           vp9block.o vp9prob.o vp9mvs.o 
vp56rac.o
 OBJS-$(CONFIG_VP9_VAAPI_ENCODER)       += vaapi_encode_vp9.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 1a2f37d..a3ff579 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -509,6 +509,7 @@ void avcodec_register_all(void)
     REGISTER_ENCODER(NVENC_H264,        nvenc_h264);
     REGISTER_ENCODER(NVENC_HEVC,        nvenc_hevc);
 #endif
+    REGISTER_ENCODER(VP8_VAAPI,         vp8_vaapi);
     REGISTER_ENCODER(VP9_VAAPI,         vp9_vaapi);
 
     /* parsers */
diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c
new file mode 100644
index 0000000..c35bfb5
--- /dev/null
+++ b/libavcodec/vaapi_encode_vp8.c
@@ -0,0 +1,261 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <va/va.h>
+#include <va/va_enc_vp8.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/common.h"
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixfmt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "vaapi_encode.h"
+
+
+typedef struct VAAPIEncodeVP8Context {
+    int qindex_idr;
+    int qindex_p;
+} VAAPIEncodeVP8Context;
+
+typedef struct VAAPIEncodeVP8Options {
+    int qindex;
+    int loop_filter_level;
+    int loop_filter_sharpness;
+} VAAPIEncodeVP8Options;
+
+
+#define vseq_var(name)     vseq->name, name
+#define vseq_field(name)   vseq->seq_fields.bits.name, name
+#define vpic_var(name)     vpic->name, name
+#define vpic_field(name)   vpic->pic_fields.bits.name, name
+
+
+static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx)
+{
+    VAAPIEncodeContext               *ctx = avctx->priv_data;
+    VAEncSequenceParameterBufferVP8 *vseq = ctx->codec_sequence_params;
+
+    vseq->frame_width  = avctx->width;
+    vseq->frame_height = avctx->height;
+
+    vseq->frame_width_scale  = 0;
+    vseq->frame_height_scale = 0;
+
+    vseq->error_resilient = 0;
+    vseq->kf_auto = 0;
+
+    if (!(ctx->va_rc_mode & VA_RC_CQP)) {
+        vseq->bits_per_second = avctx->bit_rate;
+        vseq->intra_period    = avctx->gop_size;
+    }
+
+    return 0;
+}
+
+static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx,
+                                                VAAPIEncodePicture *pic)
+{
+    VAAPIEncodeContext              *ctx = avctx->priv_data;
+    VAEncPictureParameterBufferVP8 *vpic = pic->codec_picture_params;
+    VAAPIEncodeVP8Options           *opt = ctx->codec_options;
+    int i;
+
+    vpic->reconstructed_frame = pic->recon_surface;
+
+    vpic->coded_buf = pic->output_buffer;
+
+    switch (pic->type) {
+    case PICTURE_TYPE_IDR:
+        av_assert0(pic->nb_refs == 0);
+        vpic->ref_flags.bits.force_kf = 1;
+        vpic->ref_last_frame =
+        vpic->ref_gf_frame   =
+        vpic->ref_arf_frame  =
+            VA_INVALID_SURFACE;
+        break;
+    case PICTURE_TYPE_P:
+        av_assert0(pic->nb_refs == 1);
+        vpic->ref_flags.bits.no_ref_last = 0;
+        vpic->ref_flags.bits.no_ref_gf   = 1;
+        vpic->ref_flags.bits.no_ref_arf  = 1;
+        vpic->ref_last_frame =
+        vpic->ref_gf_frame   =
+        vpic->ref_arf_frame  =
+            pic->refs[0]->recon_surface;
+        break;
+    default:
+        av_assert0(0 && "invalid picture type");
+    }
+
+    vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR);
+    vpic->pic_flags.bits.show_frame = 1;
+
+    vpic->pic_flags.bits.refresh_last            = 1;
+    vpic->pic_flags.bits.refresh_golden_frame    = 1;
+    vpic->pic_flags.bits.refresh_alternate_frame = 1;
+
+    vpic->pic_flags.bits.version = 0;
+    vpic->pic_flags.bits.loop_filter_type = 0;
+    for (i = 0; i < 4; i++)
+        vpic->loop_filter_level[i] = opt->loop_filter_level;
+    vpic->sharpness_level = opt->loop_filter_sharpness;
+
+    vpic->clamp_qindex_low  = 0;
+    vpic->clamp_qindex_high = 127;
+
+    return 0;
+}
+
+static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx,
+                                              VAAPIEncodePicture *pic,
+                                              int index, int *type,
+                                              char *data, size_t *data_len)
+{
+    VAAPIEncodeContext     *ctx = avctx->priv_data;
+    VAAPIEncodeVP8Context *priv = ctx->priv_data;
+    VAQMatrixBufferVP8 quant;
+    int i, q;
+
+    if (index > 0)
+        return AVERROR_EOF;
+
+    if (*data_len < sizeof(quant))
+        return AVERROR(EINVAL);
+    *type = VAQMatrixBufferType;
+
+    if (pic->type == PICTURE_TYPE_IDR)
+        q = priv->qindex_idr;
+    else
+        q = priv->qindex_p;
+
+    for (i = 0; i < 4; i++)
+        quant.quantization_index[i] = q;
+    for (i = 0; i < 5; i++)
+        quant.quantization_index_delta[i] = 0;
+
+    memcpy(data, &quant, *data_len = sizeof(quant));
+    return 0;
+}
+
+static av_cold int vaapi_encode_vp8_configure(AVCodecContext *avctx)
+{
+    VAAPIEncodeContext     *ctx = avctx->priv_data;
+    VAAPIEncodeVP8Context *priv = ctx->priv_data;
+    VAAPIEncodeVP8Options  *opt = ctx->codec_options;
+
+    priv->qindex_p = opt->qindex;
+    if (avctx->i_quant_factor > 0.0)
+        priv->qindex_idr = (int)((priv->qindex_p * avctx->i_quant_factor +
+                                 avctx->i_quant_offset) + 0.5);
+    else
+        priv->qindex_idr = priv->qindex_p;
+
+    return 0;
+}
+
+static const VAAPIEncodeType vaapi_encode_type_vp8 = {
+    .configure             = &vaapi_encode_vp8_configure,
+
+    .priv_data_size        = sizeof(VAAPIEncodeVP8Context),
+
+    .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP8),
+    .init_sequence_params  = &vaapi_encode_vp8_init_sequence_params,
+
+    .picture_params_size   = sizeof(VAEncPictureParameterBufferVP8),
+    .init_picture_params   = &vaapi_encode_vp8_init_picture_params,
+
+    .write_extra_buffer    = &vaapi_encode_vp8_write_quant_table,
+};
+
+static av_cold int vaapi_encode_vp8_init(AVCodecContext *avctx)
+{
+    VAAPIEncodeContext *ctx = avctx->priv_data;
+
+    if (avctx->max_b_frames > 0) {
+        av_log(avctx, AV_LOG_ERROR, "B-frames are not supported.\n");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    ctx->codec = &vaapi_encode_type_vp8;
+
+    ctx->va_profile    = VAProfileVP8Version0_3;
+    ctx->va_entrypoint = VAEntrypointEncSlice;
+    ctx->va_rt_format  = VA_RT_FORMAT_YUV420;
+
+    if (avctx->bit_rate > 0)
+        ctx->va_rc_mode = VA_RC_CBR;
+    else
+        ctx->va_rc_mode = VA_RC_CQP;
+
+    // Packed headers are not currently supported.
+    ctx->va_packed_headers = 0;
+
+    ctx->surface_width  = FFALIGN(avctx->width,  16);
+    ctx->surface_height = FFALIGN(avctx->height, 16);
+
+    return ff_vaapi_encode_init(avctx);
+}
+
+#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \
+                   offsetof(VAAPIEncodeVP8Options, x))
+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
+static const AVOption vaapi_encode_vp8_options[] = {
+    { "qindex", "Constant Q-index (for non-key frames; scaled by 
qfactor/qoffset for key frames)",
+      OFFSET(qindex), AV_OPT_TYPE_INT, { .i64 = 40 }, 0, 127, FLAGS },
+    { "loop_filter_level", "Loop filter level",
+      OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS 
},
+    { "loop_filter_sharpness", "Loop filter sharpness",
+      OFFSET(loop_filter_sharpness), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 15, 
FLAGS },
+    { NULL },
+};
+
+static const AVCodecDefault vaapi_encode_vp8_defaults[] = {
+    { "b",              "0"   },
+    { "bf",             "0"   },
+    { "g",              "120" },
+    { NULL },
+};
+
+static const AVClass vaapi_encode_vp8_class = {
+    .class_name = "vp8_vaapi",
+    .item_name  = av_default_item_name,
+    .option     = vaapi_encode_vp8_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_vp8_vaapi_encoder = {
+    .name           = "vp8_vaapi",
+    .long_name      = NULL_IF_CONFIG_SMALL("VP8 (VAAPI)"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_VP8,
+    .priv_data_size = (sizeof(VAAPIEncodeContext) +
+                       sizeof(VAAPIEncodeVP8Options)),
+    .init           = &vaapi_encode_vp8_init,
+    .encode2        = &ff_vaapi_encode2,
+    .close          = &ff_vaapi_encode_close,
+    .priv_class     = &vaapi_encode_vp8_class,
+    .capabilities   = AV_CODEC_CAP_DELAY,
+    .defaults       = vaapi_encode_vp8_defaults,
+    .pix_fmts = (const enum AVPixelFormat[]) {
+        AV_PIX_FMT_VAAPI,
+        AV_PIX_FMT_NONE,
+    },
+};
-- 
2.10.2
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to