From patchwork Sun May 31 06:29:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Guiyong" X-Patchwork-Id: 20037 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 5B77944A712 for ; Sun, 31 May 2020 09:29:31 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 303D968048C; Sun, 31 May 2020 09:29:31 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from shasxm03.verisilicon.com (unknown [101.89.135.45]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EEE10681868 for ; Sun, 31 May 2020 09:29:22 +0300 (EEST) Content-Language: en-US DKIM-Signature: v=1; a=rsa-sha256; d=Verisilicon.com; s=default; c=simple/simple; t=1590906561; h=from:subject:to:date:message-id; bh=zd602rKKol0PZ2lmX5Tj1GrNtxbq6ZOe1CnWtX6WVz4=; b=f36uvoNr/0CXUry1vOvyPMxIj5pf6khqDqby7tzjMpUbxFS5VKEkp+92/uPbIrxvA456emTd1io WAo3Yk30Ae9Tx6os1TZivIcod8NMPEPW+gtzi7/PNiijVNUKOwYKrPmXAyzzwbQS4fgqMy4BOCcPr flwREcMmYJPQS+6GnDU= Received: from SHASXM03.verisilicon.com ([fe80::938:4dda:a2f9:38aa]) by SHASXM06.verisilicon.com ([fe80::59a8:ce34:dc14:ddda%16]) with mapi id 14.03.0123.003; Sun, 31 May 2020 14:29:20 +0800 From: "Zhang, Guiyong" To: "ffmpeg-devel@ffmpeg.org" Thread-Topic: [PATCH v2 6/8] vcodec/vp9enc: Add vp9 VPE HW encoder Thread-Index: AdY3FNEGvpr6mSsySOWL8bFegAEaiA== Date: Sun, 31 May 2020 06:29:19 +0000 Message-ID: <8847CE4FAA78C048A83C2AE8AA751D2770A53756@SHASXM03.verisilicon.com> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.10.25.45] x-tm-as-product-ver: SMEX-11.0.0.4179-8.100.1062-25452.001 x-tm-as-result: No--10.783500-0.000000-31 x-tm-as-user-approved-sender: Yes x-tm-as-user-blocked-sender: No MIME-Version: 1.0 X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: [FFmpeg-devel] [PATCH v2 6/8] vcodec/vp9enc: Add vp9 VPE HW encoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This encoder uses VPI(VPE Interface) API and library for vp9 encoding. Signed-off-by: Guiyong.zhang --- configure | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/vpe_vp9enc.c | 536 ++++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/vpe_vp9enc.h | 83 ++++++++ 5 files changed, 622 insertions(+) create mode 100755 libavcodec/vpe_vp9enc.c create mode 100755 libavcodec/vpe_vp9enc.h -- 1.8.3.1 diff --git a/configure b/configure index 10d1322..0522f21 100755 --- a/configure +++ b/configure @@ -3134,6 +3134,7 @@ vp9_qsv_encoder_deps="libmfx MFX_CODEC_VP9" vp9_qsv_encoder_select="qsvenc" vp9_v4l2m2m_decoder_deps="v4l2_m2m vp9_v4l2_m2m" vp9_vpe_decoder_deps="vpe" +vp9_vpe_encoder_deps="vpe" wmv3_crystalhd_decoder_select="crystalhd" # parsers diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ffdfae4..7cf1d4e 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -766,6 +766,7 @@ OBJS-$(CONFIG_HEVC_VPE_DECODER) += vpe_hevcdec.o vpe_dec_common.o OBJS-$(CONFIG_VP9_VPE_DECODER) += vpe_vp9dec.o vpe_dec_common.o OBJS-$(CONFIG_H264_VPE_ENCODER) += vpe_h26xenc.o OBJS-$(CONFIG_HEVC_VPE_ENCODER) += vpe_h26xenc.o +OBJS-$(CONFIG_VP9_VPE_ENCODER) += vpe_vp9enc.o # (AD)PCM decoders/encoders OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 91f4e61..cebfc56 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -813,6 +813,7 @@ extern AVCodec ff_hevc_vpe_decoder; extern AVCodec ff_vp9_vpe_decoder; extern AVCodec ff_h264_vpe_encoder; extern AVCodec ff_hevc_vpe_encoder; +extern AVCodec ff_vp9_vpe_encoder; // The iterate API is not usable with ossfuzz due to the excessive size of binaries created #if CONFIG_OSSFUZZ diff --git a/libavcodec/vpe_vp9enc.c b/libavcodec/vpe_vp9enc.c new file mode 100755 index 0000000..087ddc5 --- /dev/null +++ b/libavcodec/vpe_vp9enc.c @@ -0,0 +1,536 @@ +/* + * Verisilicon VPE VP9 Encoder + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/pixfmt.h" +#include "vpe_vp9enc.h" + +#define OFFSET(x) (offsetof(VpeEncVp9Ctx, x)) +#define FLAGS \ + (AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_EXPORT) + +const static AVOption vpe_enc_vp9_options[] = { + { "preset", + "Set the encoding preset, superfast/fast/medium/slow/superslow", + OFFSET(preset), + AV_OPT_TYPE_STRING, + { .str = "fast" }, + 0, + 0, + FLAGS }, + { "effort", + "Encoder effort level, 0=fastest, 5=best quality", + OFFSET(effort), + AV_OPT_TYPE_INT, + { .i64 = 0 }, + 0, + 5, + FLAGS }, + { "lag_in_frames", + "Number of frames to lag. Up to 25. [0]", + OFFSET(lag_in_frames), + AV_OPT_TYPE_INT, + { .i64 = 0 }, + 0, + 25, + FLAGS }, + { "passes", + "Number of passes (1/2). [1]", + OFFSET(passes), + AV_OPT_TYPE_INT, + { .i64 = 1 }, + 1, + 2, + FLAGS }, + + /*Detail parameters described in + https://github.com/VeriSilicon/VPE/blob/master/doc/enc_params_vp9.md */ + { "enc_params", + "Override the enc configuration", + OFFSET(enc_params), + AV_OPT_TYPE_STRING, + { 0 }, + 0, + 0, + FLAGS }, + { NULL }, +}; + +static int vpe_vp9enc_init_hwctx(AVCodecContext *avctx) +{ + int ret = 0; + AVHWFramesContext *hwframe_ctx; + VpeEncVp9Ctx *ctx = avctx->priv_data; + + if (avctx->hw_frames_ctx) { + ctx->hw_frame = av_buffer_ref(avctx->hw_frames_ctx); + if (!ctx->hw_frame) { + ret = AVERROR(ENOMEM); + goto error; + } + + hwframe_ctx = (AVHWFramesContext *)ctx->hw_frame->data; + ctx->hw_device = av_buffer_ref(hwframe_ctx->device_ref); + if (!ctx->hw_device) { + ret = AVERROR(ENOMEM); + goto error; + } + } else { + if (avctx->hw_device_ctx) { + ctx->hw_device = av_buffer_ref(avctx->hw_device_ctx); + if (!ctx->hw_device) { + ret = AVERROR(ENOMEM); + goto error; + } + } else { + ret = av_hwdevice_ctx_create(&ctx->hw_device, AV_HWDEVICE_TYPE_VPE, + NULL, NULL, 0); + if (ret < 0) + goto error; + } + + ctx->hw_frame = av_hwframe_ctx_alloc(ctx->hw_device); + if (!ctx->hw_frame) { + ret = AVERROR(ENOMEM); + goto error; + } + } + + return ret; +error: + return ret; +} + +static void vpe_vp9enc_output_packet(AVCodecContext *avctx, VpeEncVp9Ctx *ctx, + VpiPacket *vpi_packet, + AVPacket *out_packet) +{ + memcpy(out_packet->data, vpi_packet->data, vpi_packet->size); + out_packet->size = vpi_packet->size; + out_packet->pts = vpi_packet->pts; + out_packet->dts = vpi_packet->pkt_dts; +} + +static int vpe_vp9enc_input_frame(AVCodecContext *avctx, AVFrame *input_image, + VpiFrame *out_frame) +{ + VpiFrame *in_vpi_frame; + if (input_image) { + in_vpi_frame = (VpiFrame *)input_image->data[0]; + out_frame->width = input_image->width; + out_frame->height = input_image->height; + out_frame->linesize[0] = input_image->linesize[0]; + out_frame->linesize[1] = input_image->linesize[1]; + out_frame->linesize[2] = input_image->linesize[2]; + out_frame->key_frame = input_image->key_frame; + out_frame->pts = input_image->pts; + out_frame->pkt_dts = input_image->pkt_dts; + out_frame->data[0] = in_vpi_frame->data[0]; + out_frame->data[1] = in_vpi_frame->data[1]; + out_frame->data[2] = in_vpi_frame->data[2]; + } else { + memset(out_frame, 0, sizeof(VpiFrame)); + } + + return 0; +} + +static void vpe_dump_pic(const char *str, const char *sep, VpeEncVp9Ctx *ctx, + int cur) +{ + int i = 0; + + av_log(NULL, AV_LOG_DEBUG, "%s %d\n", str, cur); + for (i = 0; i < MAX_WAIT_DEPTH; i++) { + if ((ctx->pic_wait_list[i].state == 0) && + (ctx->pic_wait_list[i].poc == 0) && + (ctx->pic_wait_list[i].trans_pic == NULL)) + continue; + + av_log(NULL, AV_LOG_DEBUG, "pic[%d] state=%d, poc=%d, data=%p", i, + ctx->pic_wait_list[i].state, ctx->pic_wait_list[i].poc, + ctx->pic_wait_list[i].trans_pic); + + if (ctx->pic_wait_list[i].poc == cur) + av_log(NULL, AV_LOG_DEBUG, "%s", sep); + av_log(NULL, AV_LOG_DEBUG, "\n"); + } + av_log(NULL, AV_LOG_DEBUG, "\n"); +} + +static int vpe_vp9enc_receive_pic(AVCodecContext *avctx, VpeEncVp9Ctx *ctx, + const AVFrame *input_image) +{ + VpeEncVp9Pic *transpic = NULL; + VpiFrame *vpi_frame; + int i; + + ctx->poc = ctx->poc + 1; + for (i = 0; i < MAX_WAIT_DEPTH; i++) { + if (ctx->pic_wait_list[i].state == 0) { + transpic = &ctx->pic_wait_list[i]; + break; + } + } + + if (i == MAX_WAIT_DEPTH) { + return AVERROR(EAGAIN); + } + + if (input_image) { + if (!transpic->trans_pic) { + transpic->trans_pic = av_frame_alloc(); + if (!transpic->trans_pic) { + return AVERROR(ENOMEM); + } + } + av_frame_unref(transpic->trans_pic); + av_frame_ref(transpic->trans_pic, input_image); + } else { + av_log(avctx, AV_LOG_DEBUG, "input image is empty\n"); + } + + transpic->state = 1; + transpic->poc = ctx->poc; + if (input_image) { + vpi_frame = (VpiFrame *)input_image->data[0]; + vpi_frame->used_cnt++; + } + + vpe_dump_pic("vpe_vp9enc_receive_pic", " <---", ctx, ctx->poc); + return 0; +} + +static int vpe_vp9enc_get_pic(AVCodecContext *avctx, VpeEncVp9Ctx *ctx, + int need_poc, AVFrame **out_image) +{ + VpeEncVp9Pic *transpic = NULL; + int i; + + vpe_dump_pic("vpe_vp9enc_get_pic", " [****]", ctx, need_poc); + for (i = 0; i < MAX_WAIT_DEPTH; i++) { + if (ctx->pic_wait_list[i].state == 1) { + transpic = &ctx->pic_wait_list[i]; + if (transpic && transpic->poc == need_poc) { + *out_image = transpic->trans_pic; + return 0; + } + } + } + + *out_image = NULL; + return -1; +} + +static int vpe_vp9enc_consume_pic(AVCodecContext *avctx, VpeEncVp9Ctx *ctx, + int consume_poc) +{ + VpeEncVp9Pic *transpic = NULL; + VpiFrame *vpi_frame; + int i; + + vpe_dump_pic("vpe_vp9enc_consume_pic", " --->", ctx, consume_poc); + for (i = 0; i < MAX_WAIT_DEPTH; i++) { + if (ctx->pic_wait_list[i].state == 1) { + transpic = &ctx->pic_wait_list[i]; + if (transpic && transpic->poc == consume_poc) { + goto find_pic; + } + } + } + if (i == MAX_WAIT_DEPTH) { + av_log(avctx, AV_LOG_ERROR, + "vpe_vp9enc_consume_pic: poc %d is not matched\n", consume_poc); + return -1; + } + +find_pic: + transpic->poc = 0; + transpic->state = 0; + vpi_frame = (VpiFrame *)transpic->trans_pic->data[0]; + vpi_frame->used_cnt--; + if (vpi_frame->used_cnt == 0) + vpi_frame->locked = 0; + + av_frame_unref(transpic->trans_pic); + transpic->trans_pic = NULL; + return 0; +} + +static av_cold int vpe_enc_vp9_free_frames(AVCodecContext *avctx) +{ + VpeEncVp9Ctx *ctx = (VpeEncVp9Ctx *)avctx->priv_data; + int frame_tobe_free = 0; + VpiCtrlCmdParam cmd; + int ret = 0; + + /* Get picture number to be free */ + cmd.cmd = VPI_CMD_VP9ENC_GET_PIC_TOBE_FREE; + ret = ctx->vpi->control(ctx->ctx, (void *)&cmd, &frame_tobe_free); + if (ret < 0) + return AVERROR_EXTERNAL; + + if (frame_tobe_free > 0) { + ret = vpe_vp9enc_consume_pic(avctx, ctx, frame_tobe_free); + if (ret != 0) + return ret; + } + + return 0; +} + +static av_cold int vpe_enc_vp9_get_frames(AVCodecContext *avctx) +{ + VpeEncVp9Ctx *ctx = (VpeEncVp9Ctx *)avctx->priv_data; + int numbers_wait_frames = 0; + int i = 0; + + for (i = 0; i < MAX_WAIT_DEPTH; i++) { + if (ctx->pic_wait_list[i].trans_pic != NULL) { + numbers_wait_frames++; + } + } + return numbers_wait_frames; +} + +static av_cold int vpe_enc_vp9_close(AVCodecContext *avctx) +{ + VpeEncVp9Ctx *ctx = avctx->priv_data; + + if (!ctx->initialized) + return 0; + + ctx->vpi->close(ctx->ctx); + + av_buffer_unref(&ctx->hw_frame); + av_buffer_unref(&ctx->hw_device); + ctx->initialized = 0; + + if (vpi_destroy(ctx->ctx)) { + return AVERROR_EXTERNAL; + } + return 0; +} + +static av_cold int vpe_enc_vp9_init(AVCodecContext *avctx) +{ + VpeEncVp9Ctx *ctx = avctx->priv_data; + AVHWFramesContext *hwframe_ctx; + AVVpeFramesContext *vpeframe_ctx; + VpiEncVp9Opition *psetting = &ctx->vp9cfg; + int ret = 0; + + if (ctx->initialized == 1) { + return 0; + } + + ret = vpe_vp9enc_init_hwctx(avctx); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "vpe_encvp9_init_hwctx failure\n"); + goto error; + } + hwframe_ctx = (AVHWFramesContext *)ctx->hw_frame->data; + vpeframe_ctx = (AVVpeFramesContext *)hwframe_ctx->hwctx; + + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + psetting->preset = ctx->preset; + psetting->effort = ctx->effort; + psetting->lag_in_frames = ctx->lag_in_frames; + psetting->passes = ctx->passes; + psetting->framectx = vpeframe_ctx->frame; + psetting->enc_params = ctx->enc_params; + psetting->width = avctx->width; + psetting->height = avctx->height; + + if ((avctx->bit_rate >= 10000) && (avctx->bit_rate <= 60000000)) { + psetting->bit_rate = avctx->bit_rate; + } else { + av_log(avctx, AV_LOG_WARNING, "invalid bit_rate=%d\n", + psetting->bit_rate); + } + + if ((avctx->bit_rate_tolerance >= 10000) && + (avctx->bit_rate_tolerance <= 60000000)) { + psetting->bit_rate_tolerance = avctx->bit_rate_tolerance; + } else { + av_log(avctx, AV_LOG_WARNING, "invalid bit_rate_tolerance=%d\n", + avctx->bit_rate_tolerance); + } + + if ((avctx->framerate.num > 0) && (avctx->framerate.num < 1048576)) { + psetting->frame_rate_numer = avctx->framerate.num; + } else { + av_log(avctx, AV_LOG_WARNING, "invalid framerate.num=%d\n", + avctx->framerate.num); + } + if ((avctx->framerate.den > 0) && (avctx->framerate.den < 1048576)) { + psetting->frame_rate_denom = avctx->framerate.den; + } else { + av_log(avctx, AV_LOG_WARNING, "invalid framerate.den=%d\n", + avctx->framerate.den); + } + + if (avctx->profile == FF_PROFILE_VP9_0 || + avctx->profile == FF_PROFILE_VP9_1) { + psetting->force_8bit = 1; + } else { + psetting->force_8bit = 0; + } + + ret = vpi_create(&ctx->ctx, &ctx->vpi, VP9ENC_VPE); + if (ret) { + ret = AVERROR_EXTERNAL; + av_log(avctx, AV_LOG_ERROR, "VP9 enc vpi_create failed\n"); + goto error; + } + + ret = ctx->vpi->init(ctx->ctx, psetting); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "VP9 enc init failed\n"); + ret = AVERROR_EXTERNAL; + goto error; + } + + ctx->initialized = 1; + ctx->poc = 0; + ctx->flush_state = 0; + memset(ctx->pic_wait_list, 0, sizeof(ctx->pic_wait_list)); + return ret; + +error: + vpe_enc_vp9_close(avctx); + return ret; +} + +static int vpe_enc_vp9_send_frame(AVCodecContext *avctx, + const AVFrame *input_frame) +{ + VpeEncVp9Ctx *ctx = (VpeEncVp9Ctx *)avctx->priv_data; + VpiCtrlCmdParam cmd; + int numbers_wait_frames = 0; + int ret = 0; + + /* Store input pictures */ + ret = vpe_vp9enc_receive_pic(avctx, ctx, input_frame); + if (ret != 0) { + return ret; + } + + /* Get back encoder wait list frames and send back to codec */ + numbers_wait_frames = vpe_enc_vp9_get_frames(avctx); + + /* Tell encoder how many frames are waitting for encoding*/ + cmd.cmd = VPI_CMD_VP9ENC_SET_PENDDING_FRAMES_COUNT; + cmd.data = &numbers_wait_frames; + ret = ctx->vpi->control(ctx->ctx, (void *)&cmd, NULL); + if (ret != 0) { + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int vpe_enc_vp9_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) +{ + AVFrame *pic = NULL; + VpeEncVp9Ctx *ctx = (VpeEncVp9Ctx *)avctx->priv_data; + VpiFrame vpi_frame; + VpiPacket vpi_packet; + VpiCtrlCmdParam cmd; + int next_frame = 0, inputs = 0; + int ret = 0, ret1 = 0; + int buffer_size = 0; + + /* Get next picture number to be encoded */ + cmd.cmd = VPI_CMD_VP9ENC_GET_NEXT_PIC; + ret = ctx->vpi->control(ctx->ctx, &cmd, &next_frame); + if (ret != 0) + return AVERROR_EXTERNAL; + + /* Get next picture to be encoded */ + ret = vpe_vp9enc_get_pic(avctx, ctx, next_frame + 1, &pic); + if (ret != 0) + return AVERROR(EAGAIN); + + inputs = vpe_enc_vp9_get_frames(avctx); + if (inputs == 0) { + av_log(avctx, AV_LOG_DEBUG, "Input Q was empty, send EOF\n"); + return AVERROR_EOF; + } + + /* Convert input picture from AVFrame to VpiFrame*/ + ret = vpe_vp9enc_input_frame(avctx, pic, &vpi_frame); + if (ret != 0) + return AVERROR_EXTERNAL; + + /*Allocate AVPacket bufffer*/ + buffer_size = (avctx->width * avctx->height * 3) / 4; + buffer_size += buffer_size / 2; + buffer_size &= (~4095); + ret = av_new_packet(avpkt, buffer_size); + if (ret != 0) + return ret; + + vpi_packet.data = avpkt->data; + ret = ctx->vpi->encode(ctx->ctx, (void *)&vpi_frame, (void *)&vpi_packet); + if (ret == 0) { + if (vpi_packet.size == 0) { + av_packet_unref(avpkt); + ret = AVERROR(EAGAIN); + goto exit; + } + /*Convert output packet from VpiPacket to AVPacket*/ + vpe_vp9enc_output_packet(avctx, ctx->ctx, &vpi_packet, avpkt); + } else { + av_log(avctx, AV_LOG_ERROR, "VP9 enc encode failed\n"); + ret = AVERROR_EXTERNAL; + } + +exit: + ret1 = vpe_enc_vp9_free_frames(avctx); + if (ret != 0) + return ret; + else + return ret1; +} + +static const AVClass vpe_enc_vp9_class = { + .class_name = "vp9enc_vpe", + .item_name = av_default_item_name, + .option = vpe_enc_vp9_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_vp9_vpe_encoder = { + .name = "vp9enc_vpe", + .long_name = NULL_IF_CONFIG_SMALL("VP9 (VPE BIGSEA)"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP9, + .priv_data_size = sizeof(VpeEncVp9Ctx), + .init = &vpe_enc_vp9_init, + .send_frame = &vpe_enc_vp9_send_frame, + .receive_packet = &vpe_enc_vp9_receive_packet, + .close = &vpe_enc_vp9_close, + .priv_class = &vpe_enc_vp9_class, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, + .pix_fmts = + (const enum AVPixelFormat[]){ AV_PIX_FMT_VPE, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE }, + .wrapper_name = "vpe", +}; diff --git a/libavcodec/vpe_vp9enc.h b/libavcodec/vpe_vp9enc.h new file mode 100755 index 0000000..a93b11a --- /dev/null +++ b/libavcodec/vpe_vp9enc.h @@ -0,0 +1,83 @@ +/* + * Verisilicon VPE VP9 Encoder head file + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef VPE_ENCVP9_H +#define VPE_ENCVP9_H + +#include + +#include +#include + +#include "avcodec.h" +#include "libavutil/log.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_vpe.h" +#include "libavutil/buffer.h" +#include "libavutil/error.h" +#include "libavutil/frame.h" +#include "libavutil/opt.h" + +#define MAX_WAIT_DEPTH 44 + +typedef struct { + int state; + int poc; + AVFrame *trans_pic; +} VpeEncVp9Pic; + +/* + * Private VPE VP9 encoder hardware structure + */ +typedef struct { + const AVClass *av_class; + /*The hardware device context*/ + AVBufferRef *hw_device; + /*The hardware frame context containing the input frames*/ + AVBufferRef *hw_frame; + /*VPI main context*/ + VpiCtx ctx; + /*VPE codec function pointer*/ + VpiApi *vpi; + /*VPE init state*/ + uint32_t initialized; + /*Input avframe queue*/ + VpeEncVp9Pic pic_wait_list[MAX_WAIT_DEPTH]; + /*Input avframe index*/ + int poc; + + /*Encoder config*/ + VpiEncVp9Opition vp9cfg; + /*Set the encoding preset, superfast/fast/medium/slow/superslow*/ + char *preset; + /*Encoder effort level*/ + int effort; + /*Number of frames to lag. */ + int lag_in_frames; + /*"Number of encoding passes*/ + int passes; + /*More encoding parameters*/ + char *enc_params; + /*Encoder flush state*/ + int flush_state; +} VpeEncVp9Ctx; + + +#endif /*VPE_ENCVP9_H*/