[FFmpeg-devel] [PATCH] avcodec/h264bsd_dec: add h264dec base on h264bsd
Shiqi Zhu
hiccupzhu at gmail.com
Wed Apr 16 09:12:21 EEST 2025
h264bsd url https://github.com/oneam/h264bsd
./configure --enable-decoder="h264_bsd" --extra-cflags="-I<path>/h264bsd/src" --extra-ldflags="-L<path>/h264bsd/posix/lib" --extra-libs="-lh264bsd"
Test
./ffmpeg -y -codec:v h264_bsd -i <path>/h264bsd/test/test_640x360.h264 ./test_640x360.yuv
Signed-off-by: Shiqi Zhu <hiccupzhu at gmail.com>
---
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/h264bsd_dec.c | 183 +++++++++++++++++++++++++++++++++++++++
3 files changed, 185 insertions(+)
create mode 100644 libavcodec/h264bsd_dec.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 7bd1dbec9a..68cfc3abb5 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -419,6 +419,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \
h264_slice.o h264data.o h274.o
OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o
OBJS-$(CONFIG_H264_AMF_DECODER) += amfdec.o
+OBJS-$(CONFIG_H264_BSD_DECODER) += h264bsd_dec.o
OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o
OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f10519617e..a752f83210 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -148,6 +148,7 @@ extern const FFCodec ff_h263i_decoder;
extern const FFCodec ff_h263p_encoder;
extern const FFCodec ff_h263p_decoder;
extern const FFCodec ff_h263_v4l2m2m_decoder;
+extern const FFCodec ff_h264_bsd_decoder;
extern const FFCodec ff_h264_decoder;
extern const FFCodec ff_h264_v4l2m2m_decoder;
extern const FFCodec ff_h264_mediacodec_decoder;
diff --git a/libavcodec/h264bsd_dec.c b/libavcodec/h264bsd_dec.c
new file mode 100644
index 0000000000..e687dbf8e3
--- /dev/null
+++ b/libavcodec/h264bsd_dec.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2025 Shiqi Zhu <hiccupzhu at gmail.com>
+ * 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
+ */
+
+/**
+ * @file
+ * MCV hardware video decoder
+ */
+
+#include "config_components.h"
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "internal.h"
+#include "packet.h"
+#include "libavutil/opt.h"
+#include "libavutil/fifo.h"
+#include "h264bsd_decoder.h"
+
+typedef struct DecodeContext {
+ AVClass *av_class;
+ storage_t vdec;
+ AVCodecContext *avctx;
+ uint32_t ext_buffer_num;
+ int coded_width;
+ int coded_height;
+ enum AVPixelFormat format;
+} DecodeContext;
+
+static av_cold int h264_bsd_init_decoder(AVCodecContext *avctx)
+{
+ DecodeContext *x = avctx->priv_data;
+ int ret;
+
+ ret = h264bsdInit(&x->vdec, 0);
+ if (ret != 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to open hifi decoder\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ x->avctx = avctx;
+ x->format = AV_PIX_FMT_YUV420P;
+
+ return 0;
+}
+
+static av_cold int h264_bsd_close_decoder(AVCodecContext *avctx)
+{
+ DecodeContext *x = avctx->priv_data;
+ int ret;
+
+ x->avctx = NULL;
+ h264bsdShutdown(&x->vdec);
+
+ return 0;
+}
+
+static void h264_bsd_flush(AVCodecContext *avctx)
+{
+ DecodeContext *x = avctx->priv_data;
+
+ h264bsdFlushBuffer(&x->vdec);
+}
+
+static int h264_bsd_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+ int *got_frame, AVPacket *avpkt)
+{
+ DecodeContext *x = avctx->priv_data;
+ int ret, i, w, h;
+ uint32_t readBytes;
+ int numPics = 0;
+ uint32_t picId, isIdrPic, numErrMbs;
+ uint8_t *data;
+
+ while (avpkt->size > 0) {
+ ret = h264bsdDecode(&x->vdec, avpkt->data, avpkt->size, 0, &readBytes);
+ avpkt->data += readBytes;
+ avpkt->size -= readBytes;
+
+ switch (ret)
+ {
+ case H264BSD_PIC_RDY:
+ data = h264bsdNextOutputPicture(&x->vdec, &picId, &isIdrPic, &numErrMbs);
+ if (isIdrPic) {
+ av_log(avctx, AV_LOG_DEBUG, "IDR picture %d\n", picId);
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "Non-IDR picture %d\n", picId);
+ }
+ if (numErrMbs > 0) {
+ av_log(avctx, AV_LOG_DEBUG, "Picture %d has %d errors\n", picId, numErrMbs);
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "Picture %d has no errors\n", picId);
+ }
+
+ frame->width = avctx->width;
+ frame->height = avctx->height;
+ frame->format = x->format;
+ ret = avcodec_default_get_buffer2(avctx, frame, 0);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to get buffer\n");
+ return ret;
+ }
+
+ for (h = 0; h < frame->height; h++) {
+ memcpy(frame->data[0] + h * frame->linesize[0], data + h * x->coded_width, frame->width);
+ }
+ data += x->coded_width * x->coded_height;
+ w = x->coded_width >> 1;
+ for (i = 1; i < 3; i++) {
+ for (h = 0; h < (frame->height >> 1); h++) {
+ memcpy(frame->data[i] + h * frame->linesize[i], data + h * w, frame->width >> 1);
+ }
+ data += w * h;
+ }
+ frame->pts = avpkt->pts;
+ frame->pkt_dts = avpkt->dts;
+ frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
+ *got_frame = 1;
+ break;
+ case H264BSD_HDRS_RDY:
+ x->coded_width = h264bsdPicWidth(&x->vdec) * 16;
+ x->coded_height = h264bsdPicHeight(&x->vdec) * 16;
+ av_log(avctx, AV_LOG_INFO, "Output dimensions: %dx%d\n", w, h);
+ break;
+
+ case H264BSD_RDY:
+ av_log(avctx, AV_LOG_DEBUG, "Picture %d is ready\n", picId);
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Error decoding frame: %d\n", ret);
+ goto out;
+ }
+ }
+
+out:
+ return avpkt->size;
+}
+
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ {"ext_buffer_num", "extra buffer number", offsetof(DecodeContext, ext_buffer_num), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 16, VD},
+ {NULL}
+};
+
+static const AVClass h264_bsd_dec_class = {
+ .class_name = "h264_bsd_decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const FFCodec ff_h264_bsd_decoder = {
+ .p.name = "h264_bsd",
+ CODEC_LONG_NAME("h264bsd video decoder for ffmpeg"),
+ .p.type = AVMEDIA_TYPE_VIDEO,
+ .p.id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(DecodeContext),
+ .init = h264_bsd_init_decoder,
+ .close = h264_bsd_close_decoder,
+ FF_CODEC_DECODE_CB(h264_bsd_decode_frame),
+ .flush = h264_bsd_flush,
+ .p.priv_class = &h264_bsd_dec_class,
+ .bsfs = "h264_mp4toannexb",
+ .p.capabilities = AV_CODEC_CAP_DELAY,
+ .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
+ .p.wrapper_name = "ff_h264_bsd_decoder",
+ .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING,
+};
\ No newline at end of file
--
2.34.1
More information about the ffmpeg-devel
mailing list