[FFmpeg-devel] [PATCH 2/8] avcodec/h264dec: Add h264 VPE HW decoder
Zhang, Guiyong
Guiyong.Zhang at verisilicon.com
Thu May 28 08:07:17 EEST 2020
VPE(Video Pipeline Engine) is VeriSilicon's hardware engine
for multi formats video encoding and decoding.
This decoder uses VPI(VPE Interface) API and library for h264 decoding.
Signed-off-by: Qin.Wang <Qin.Wang at verisilicon.com>
---
configure | 1 +
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/version.h | 2 +-
libavcodec/vpe_dec_common.c | 476 ++++++++++++++++++++++++++++++++++++
libavcodec/vpe_dec_common.h | 81 ++++++
libavcodec/vpe_h264dec.c | 69 ++++++
7 files changed, 630 insertions(+), 1 deletion(-)
create mode 100644 libavcodec/vpe_dec_common.c
create mode 100644 libavcodec/vpe_dec_common.h
create mode 100644 libavcodec/vpe_h264dec.c
diff --git a/configure b/configure
index cf7d1d9fcc..a913b6fc68 100755
--- a/configure
+++ b/configure
@@ -3063,6 +3063,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 6d816308c7..28d5b21cb5 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -760,6 +760,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 eb5044f80e..0742c228e2 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -806,6 +806,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/version.h b/libavcodec/version.h
index 2d2cc69ab6..91002dc0b9 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 58
-#define LIBAVCODEC_VERSION_MINOR 88
+#define LIBAVCODEC_VERSION_MINOR 89
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavcodec/vpe_dec_common.c b/libavcodec/vpe_dec_common.c
new file mode 100644
index 0000000000..c4d99472a7
--- /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 0000000000..d3bc84ab20
--- /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 <stdint.h>
+
+#include <vpe/vpi_api.h>
+#include <vpe/vpi_types.h>
+
+#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 0000000000..1e530da0d0
--- /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",
+};
--
2.19.1
More information about the ffmpeg-devel
mailing list