From patchwork Sun May 31 06:26:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Guiyong" X-Patchwork-Id: 20033 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 35B6B449D3F for ; Sun, 31 May 2020 09:26:37 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0345468826C; Sun, 31 May 2020 09:26:37 +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 B14B468803D for ; Sun, 31 May 2020 09:26:29 +0300 (EEST) Content-Language: en-US DKIM-Signature: v=1; a=rsa-sha256; d=Verisilicon.com; s=default; c=simple/simple; t=1590906385; h=from:subject:to:date:message-id; bh=gqaV617v+FYbifjE0gkxgDtQN44bVnOnLIcIn0gvWI0=; b=fZyLWaJ0eLVYY3mMVan0qgY742un30chGRGcb5AczfyzM8ufHwMvQCLhhHeri6+LPBX9lk6gjn4 1CPx4zImVVjiPBaMhjYLIfEGKfvsLiCGqeY7UeDM9GG3TEqHEBKuikaq2RxPiJRPIDqxms2abqlAl moqV/A4Ll1kZ4qduxNQ= 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:26:24 +0800 From: "Zhang, Guiyong" To: "ffmpeg-devel@ffmpeg.org" Thread-Topic: [PATCH v2 2/8] avcodec/h264dec: Add h264 VPE HW decoder Thread-Index: AdY3FGfuWILhYoHhQDejtMPDGNVeuw== Date: Sun, 31 May 2020 06:26:23 +0000 Message-ID: <8847CE4FAA78C048A83C2AE8AA751D2770A53722@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--4.544700-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 2/8] avcodec/h264dec: Add h264 VPE HW decoder 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 decoder uses VPI(VPE Interface) API and library for h264 decoding. Signed-off-by: Qin.Wang --- configure | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/vpe_dec_common.c | 476 ++++++++++++++++++++++++++++++++++++++++++++ libavcodec/vpe_dec_common.h | 81 ++++++++ libavcodec/vpe_h264dec.c | 69 +++++++ 6 files changed, 629 insertions(+) create mode 100644 libavcodec/vpe_dec_common.c create mode 100644 libavcodec/vpe_dec_common.h create mode 100644 libavcodec/vpe_h264dec.c -- 1.8.3.1 diff --git a/configure b/configure index 7f0f843..196842a 100755 --- a/configure +++ b/configure @@ -3064,6 +3064,7 @@ h264_vaapi_encoder_select="cbs_h264 vaapi_encode" h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" +h264_vpe_decoder_deps="vpe" hevc_amf_encoder_deps="amf" hevc_cuvid_decoder_deps="cuvid" hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 0a3bbc7..0c80880 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -761,6 +761,7 @@ OBJS-$(CONFIG_ZLIB_DECODER) += lcldec.o OBJS-$(CONFIG_ZLIB_ENCODER) += lclenc.o OBJS-$(CONFIG_ZMBV_DECODER) += zmbv.o OBJS-$(CONFIG_ZMBV_ENCODER) += zmbvenc.o +OBJS-$(CONFIG_H264_VPE_DECODER) += vpe_h264dec.o vpe_dec_common.o # (AD)PCM decoders/encoders OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 5240d0a..32f6fd6 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -808,6 +808,7 @@ extern AVCodec ff_vp9_mediacodec_decoder; extern AVCodec ff_vp9_qsv_decoder; extern AVCodec ff_vp9_vaapi_encoder; extern AVCodec ff_vp9_qsv_encoder; +extern AVCodec ff_h264_vpe_decoder; // The iterate API is not usable with ossfuzz due to the excessive size of binaries created #if CONFIG_OSSFUZZ diff --git a/libavcodec/vpe_dec_common.c b/libavcodec/vpe_dec_common.c new file mode 100644 index 0000000..c4d9947 --- /dev/null +++ b/libavcodec/vpe_dec_common.c @@ -0,0 +1,476 @@ +/* + * Verisilicon VPE Video Decoder Common interface + * + * 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 "decode.h" +#include "internal.h" + +#include "vpe_dec_common.h" + +/** + * Initialize hw frame and device + * + * The avctx->hw_frames_ctx is the reference to the AVHWFramesContext. + * If it exists, get its data, otherwise create the hw_frame_ctx + * then initialize hw_frame_ctx. + */ +static int vpe_dec_init_hwctx(AVCodecContext *avctx) +{ + int ret = 0; + AVHWFramesContext *hwframe_ctx; + + if (!avctx->hw_frames_ctx) { + if (avctx->hw_device_ctx) { + avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); + if (!avctx->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n"); + ret = AVERROR(ENOMEM); + goto error; + } + } else { + av_log(avctx, AV_LOG_ERROR, "No hw frame/device available\n"); + ret = AVERROR(EINVAL); + goto error; + } + } + + hwframe_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + hwframe_ctx->format = AV_PIX_FMT_VPE; + if (avctx->bits_per_raw_sample == 10) { + hwframe_ctx->sw_format = AV_PIX_FMT_P010LE; + } else { + hwframe_ctx->sw_format = AV_PIX_FMT_NV12; + } + hwframe_ctx->width = avctx->width; + hwframe_ctx->height = avctx->height; + if ((ret = av_hwframe_ctx_init(avctx->hw_frames_ctx)) < 0) { + av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_init failed\n"); + return ret; + } + return 0; + +error: + av_log(avctx, AV_LOG_ERROR, "vpe_dec_init_hwctx failed\n"); + return ret; +} + +/** + * Notify the external decoder to release frame buffer + */ +static void vpe_decode_picture_consume(VpeDecCtx *dec_ctx, VpiFrame *vpi_frame) +{ + VpiCtrlCmdParam cmd_param; + + // make decoder release DPB + cmd_param.cmd = VPI_CMD_DEC_PIC_CONSUME; + cmd_param.data = (void *)vpi_frame; + dec_ctx->vpi->control(dec_ctx->ctx, (void *)&cmd_param, NULL); +} + +int ff_vpe_decode_init(AVCodecContext *avctx, VpiPlugin type) +{ + AVHWFramesContext *hwframe_ctx; + AVVpeFramesContext *vpeframe_ctx; + VpeDecCtx *dec_ctx = avctx->priv_data; + VpiCtrlCmdParam cmd_param; + int ret; + + // Init vpe hwcontext + ret = vpe_dec_init_hwctx(avctx); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "vpe init hwctx failure\n"); + return ret; + } + + hwframe_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + vpeframe_ctx = (AVVpeFramesContext *)hwframe_ctx->hwctx; + + // Create the VPE context + ret = vpi_create(&dec_ctx->ctx, &dec_ctx->vpi, type); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "vpi create failure ret %d\n", ret); + return AVERROR_EXTERNAL; + } + + // get the decoder init option struct + cmd_param.cmd = VPI_CMD_DEC_INIT_OPTION; + ret = dec_ctx->vpi->control(dec_ctx->ctx, (void *)&cmd_param, (void *)&dec_ctx->dec_setting); + if (ret != 0) { + return AVERROR(ENOMEM); + } + + dec_ctx->avctx = avctx; + dec_ctx->dec_setting->pp_setting = dec_ctx->pp_setting; + dec_ctx->dec_setting->transcode = dec_ctx->transcode; + dec_ctx->dec_setting->frame = vpeframe_ctx->frame; + avctx->pix_fmt = AV_PIX_FMT_VPE; + + // Initialize the VPE decoder + ret = dec_ctx->vpi->init(dec_ctx->ctx, dec_ctx->dec_setting); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "vpi decode init failure\n"); + return AVERROR_EXTERNAL; + } + + // get the packet buffer struct info from external decoder + // to store the avpk buf info + cmd_param.cmd = VPI_CMD_DEC_GET_STRM_BUF_PKT; + ret = dec_ctx->vpi->control(dec_ctx->ctx, (void *)&cmd_param, (void *)&dec_ctx->buffered_pkt); + if (ret != 0) { + return AVERROR(ENOMEM); + } + + return 0; +} + +/** + * clear the unsed frames + */ +static void vpe_clear_unused_frames(VpeDecCtx *dec_ctx) +{ + VpeDecFrame *cur_frame = dec_ctx->frame_list; + + while (cur_frame) { + if (cur_frame->used && !cur_frame->vpi_frame->locked) { + vpe_decode_picture_consume(dec_ctx, cur_frame->vpi_frame); + cur_frame->used = 0; + av_frame_unref(cur_frame->av_frame); + } + cur_frame = cur_frame->next; + } +} + +/** + * alloc frame from hwcontext for external codec + */ +static int vpe_alloc_frame(AVCodecContext *avctx, VpeDecCtx *dec_ctx, VpeDecFrame *dec_frame) +{ + int ret; + + ret = ff_get_buffer(avctx, dec_frame->av_frame, AV_GET_BUFFER_FLAG_REF); + if (ret < 0) { + av_log(NULL, AV_LOG_DEBUG, "return ret %d\n", ret); + return ret; + } + + dec_frame->vpi_frame = (VpiFrame*)dec_frame->av_frame->data[0]; + dec_frame->used = 1; + + return 0; +} + +/** + * get frame from the linked list + */ +static int vpe_get_frame(AVCodecContext *avctx, VpeDecCtx *dec_ctx, VpiFrame **vpi_frame) +{ + VpeDecFrame *dec_frame, **last; + int ret; + + vpe_clear_unused_frames(dec_ctx); + + dec_frame = dec_ctx->frame_list; + last = &dec_ctx->frame_list; + while (dec_frame) { + if (!dec_frame->used) { + ret = vpe_alloc_frame(avctx, dec_ctx, dec_frame); + if (ret < 0) + return ret; + *vpi_frame = dec_frame->vpi_frame; + return 0; + } + + last = &dec_frame->next; + dec_frame = dec_frame->next; + } + + dec_frame = av_mallocz(sizeof(*dec_frame)); + if (!dec_frame) + return AVERROR(ENOMEM); + dec_frame->av_frame = av_frame_alloc(); + if (!dec_frame->av_frame) { + av_freep(&dec_frame); + return AVERROR(ENOMEM); + } + *last = dec_frame; + + ret = vpe_alloc_frame(avctx, dec_ctx, dec_frame); + if (ret < 0) + return ret; + + *vpi_frame = dec_frame->vpi_frame; + + return 0; +} + +/** + * find frame from the linked list + */ +static VpeDecFrame *vpe_find_frame(VpeDecCtx *dec_ctx, VpiFrame *vpi_frame) +{ + VpeDecFrame *cur_frame = dec_ctx->frame_list; + + while (cur_frame) { + if (vpi_frame == cur_frame->vpi_frame) + return cur_frame; + cur_frame = cur_frame->next; + } + return NULL; +} + +/** + * Output the frame raw data + */ +static int vpe_output_frame(AVCodecContext *avctx, VpiFrame *vpi_frame, + AVFrame *out_frame) +{ + VpeDecCtx *dec_ctx = avctx->priv_data; + VpeDecFrame *dec_frame = NULL; + AVFrame *src_frame = NULL; + int ret; + + dec_frame = vpe_find_frame(dec_ctx, vpi_frame); + if (dec_frame == NULL) { + av_log(avctx, AV_LOG_ERROR, "Can't find matched frame from pool\n"); + return AVERROR_BUG; + } + src_frame = dec_frame->av_frame; + ret = av_frame_ref(out_frame, src_frame); + if (ret < 0) + return ret; + + out_frame->linesize[0] = vpi_frame->linesize[0]; + out_frame->linesize[1] = vpi_frame->linesize[1]; + out_frame->linesize[2] = vpi_frame->linesize[2]; + out_frame->key_frame = vpi_frame->key_frame; + out_frame->pts = vpi_frame->pts; + out_frame->pkt_dts = vpi_frame->pkt_dts; + + out_frame->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); + if (!out_frame->hw_frames_ctx) { + ret = AVERROR(ENOMEM); + } + + return 0; +} + +/** + * receive VpiFrame from external decoder + */ +static int vpe_dec_receive(AVCodecContext *avctx, AVFrame *frame) +{ + VpeDecCtx *dec_ctx = avctx->priv_data; + VpiFrame *vpi_frame = NULL; + int ret; + + vpe_clear_unused_frames(dec_ctx); + ret = dec_ctx->vpi->decode_get_frame(dec_ctx->ctx, (void *)&vpi_frame); + if (ret == 1) { + // get one output frame + if (0 == vpe_output_frame(avctx, vpi_frame, frame)) { + return 0; + } else { + return AVERROR_EXTERNAL; + } + } else if (ret == 2) { + return AVERROR_EOF; + } else { + return AVERROR(EAGAIN); + } +} + +/** + * release avpkt buf which is released by external decoder + */ +static int vpe_release_stream_mem(VpeDecCtx *dec_ctx) +{ + VpiCtrlCmdParam cmd_param; + AVBufferRef *ref = NULL; + int ret; + + cmd_param.cmd = VPI_CMD_DEC_GET_USED_STRM_MEM; + /* get the used packet buffer info from external decoder */ + ret = dec_ctx->vpi->control(dec_ctx->ctx, (void *)&cmd_param, (void *)&ref); + if (ret != 0) { + return AVERROR_EXTERNAL; + } + if (ref) { + /* unref the input avpkt buffer */ + av_buffer_unref(&ref); + return 1; + } + return 0; +} + +int ff_vpe_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + VpeDecCtx *dec_ctx = avctx->priv_data; + AVPacket avpkt = { 0 }; + AVBufferRef *ref = NULL; + VpiFrame *in_vpi_frame = NULL; + VpiCtrlCmdParam cmd_param; + int strm_buf_count; + int ret; + + ret = vpe_release_stream_mem(dec_ctx); + if (ret < 0) { + return ret; + } + /* poll for new frame */ + ret = vpe_dec_receive(avctx, frame); + if (ret != AVERROR(EAGAIN)) { + return ret; + } + + /* feed decoder */ + while (1) { + cmd_param.cmd = VPI_CMD_DEC_STRM_BUF_COUNT; + cmd_param.data = NULL; + ret = dec_ctx->vpi->control(dec_ctx->ctx, + (void*)&cmd_param, (void *)&strm_buf_count); + if (ret != 0) { + return AVERROR_EXTERNAL; + } + if (strm_buf_count == -1) { + /* no space, block for an output frame to get space */ + ret = vpe_dec_receive(avctx, frame); + if (ret != AVERROR(EAGAIN)) { + return ret; + } else { + continue; + } + } + + ret = vpe_release_stream_mem(dec_ctx); + if (ret < 0) { + return ret; + } + + /* fetch new packet or eof */ + ret = ff_decode_get_packet(avctx, &avpkt); + if (ret == 0) { + dec_ctx->buffered_pkt->data = avpkt.data; + dec_ctx->buffered_pkt->size = avpkt.size; + dec_ctx->buffered_pkt->pts = avpkt.pts; + dec_ctx->buffered_pkt->pkt_dts = avpkt.dts; + ref = av_buffer_ref(avpkt.buf); + if (!ref) { + av_packet_unref(&avpkt); + return AVERROR(ENOMEM); + } + /* ref the avpkt buffer + feed the packet buffer related info to external decoder */ + dec_ctx->buffered_pkt->opaque = (void *)ref; + av_packet_unref(&avpkt); + + /* get frame buffer from pool */ + ret = vpe_get_frame(avctx, dec_ctx, &in_vpi_frame); + if (ret < 0) { + return ret; + } + + cmd_param.cmd = VPI_CMD_DEC_SET_FRAME_BUFFER; + cmd_param.data = (void *)in_vpi_frame; + ret = dec_ctx->vpi->control(dec_ctx->ctx, (void *)&cmd_param, NULL); + if (ret != 0) { + return AVERROR_EXTERNAL; + } + } else if (ret == AVERROR_EOF) { + ret = dec_ctx->vpi->decode_put_packet(dec_ctx->ctx, + (void *)dec_ctx->buffered_pkt); + if (ret < 0) { + return AVERROR_EXTERNAL; + } else { + return AVERROR(EAGAIN); + } + } else if (ret == AVERROR(EAGAIN)) { + return vpe_dec_receive(avctx, frame); + } else if (ret < 0) { + return ret; + } + + /* try to flush packet data */ + if (dec_ctx->buffered_pkt->size > 0) { + ret = dec_ctx->vpi->decode_put_packet(dec_ctx->ctx, + (void *)dec_ctx->buffered_pkt); + if (ret > 0) { + dec_ctx->buffered_pkt->size -= ret; + if (dec_ctx->buffered_pkt->size != 0) { + return AVERROR_EXTERNAL; + } + return vpe_dec_receive(avctx, frame); + } else if (ret <= 0) { + return AVERROR_EXTERNAL; + } + } + } + + return AVERROR(EAGAIN); +} + + +av_cold int ff_vpe_decode_close(AVCodecContext *avctx) +{ + VpeDecCtx *dec_ctx = avctx->priv_data; + VpeDecFrame *cur_frame; + int ret; + + vpe_clear_unused_frames(dec_ctx); + if (dec_ctx->ctx == NULL) { + return 0; + } + dec_ctx->vpi->close(dec_ctx->ctx); + do { + ret = vpe_release_stream_mem(dec_ctx); + } while (ret == 1); + + cur_frame = dec_ctx->frame_list; + while (cur_frame) { + dec_ctx->frame_list = cur_frame->next; + av_frame_free(&cur_frame->av_frame); + av_freep(&cur_frame); + cur_frame = dec_ctx->frame_list; + } + vpi_destroy(dec_ctx->ctx); + + return 0; +} + +#define OFFSET(x) offsetof(VpeDecCtx, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +const AVOption vpe_decode_options[] = { + { "low_res", + "set output number and at most four output downscale configuration", + OFFSET(pp_setting), + AV_OPT_TYPE_STRING, + { .str = "" }, + 0, + 0, + VD }, + { "transcode", + "enable/disable transcoding", + OFFSET(transcode), + AV_OPT_TYPE_BOOL, + { .i64 = 0 }, + 0, + 1, + VD }, + { NULL }, +}; diff --git a/libavcodec/vpe_dec_common.h b/libavcodec/vpe_dec_common.h new file mode 100644 index 0000000..d3bc84a --- /dev/null +++ b/libavcodec/vpe_dec_common.h @@ -0,0 +1,81 @@ +/* + * Verisilicon VPE Video Decoder Common interface + * + * 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 AVCODEC_VPE_DEC_COMMON_H +#define AVCODEC_VPE_DEC_COMMON_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" + +extern const AVOption vpe_decode_options[]; + +typedef struct VpeDecFrame { + AVFrame *av_frame; + // frame structure used for external codec + VpiFrame *vpi_frame; + // vpi_frame has been used + int used; + // the next linked list item + struct VpeDecFrame *next; +} VpeDecFrame; + +/** + * Communicating VPE parameters between libavcodec and the caller. + */ +typedef struct VpeDecCtx { + AVClass *av_class; + AVCodecContext *avctx; + + // VPI codec/filter context + VpiCtx ctx; + // VPI codec/filter API + VpiApi *vpi; + + // VPE decodec setting parameters + DecOption *dec_setting; + + // VPE decoder resieze config + uint8_t *pp_setting; + // VPE transcode enable + int transcode; + + // buffered packet feed to external decoder + VpiPacket *buffered_pkt; + + // VPE frame linked list + VpeDecFrame *frame_list; +} VpeDecCtx; + +int ff_vpe_decode_init(AVCodecContext *avctx, VpiPlugin type); +int ff_vpe_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame); +int ff_vpe_decode_close(AVCodecContext *avctx); + +#endif /*AVCODEC_VPE_DEC_COMMON_H*/ diff --git a/libavcodec/vpe_h264dec.c b/libavcodec/vpe_h264dec.c new file mode 100644 index 0000000..1e530da --- /dev/null +++ b/libavcodec/vpe_h264dec.c @@ -0,0 +1,69 @@ +/* + * Verisilicon VPE H264 Decoder + * + * 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 "hwconfig.h" +#include "internal.h" +#include "libavutil/pixfmt.h" + +#include "vpe_dec_common.h" + +static av_cold int vpe_h264_decode_init(AVCodecContext *avctx) +{ + return ff_vpe_decode_init(avctx, H264DEC_VPE); +} + +static const AVClass vpe_h264_decode_class = { + .class_name = "h264d_vpe", + .item_name = av_default_item_name, + .option = vpe_decode_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecHWConfigInternal *vpe_hw_configs[] = + { &(const AVCodecHWConfigInternal){ + .public = + { + .pix_fmt = AV_PIX_FMT_VPE, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, + .device_type = AV_HWDEVICE_TYPE_VPE, + }, + .hwaccel = NULL, + }, + NULL }; + +AVCodec ff_h264_vpe_decoder = { + .name = "h264_vpe", + .long_name = NULL_IF_CONFIG_SMALL("H264 (VPE VC8000D)"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .priv_data_size = sizeof(VpeDecCtx), + .init = &vpe_h264_decode_init, + .receive_frame = &ff_vpe_decode_receive_frame, + .close = &ff_vpe_decode_close, + .priv_class = &vpe_h264_decode_class, + .capabilities = + AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_AVOID_PROBING, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VPE, AV_PIX_FMT_NONE }, + .hw_configs = vpe_hw_configs, + .wrapper_name = "vpe", + .bsfs = "h264_mp4toannexb", +};