From 8d5d8b93350952f2280a4024503bc1c3e07ba54b Mon Sep 17 00:00:00 2001 From: SiruiLiao <46930277+Liaosrl@users.noreply.github.com> Date: Tue, 16 Apr 2024 14:18:45 +0800 Subject: [PATCH] Add FFmpeg 6.0.1 plugin patch for HW265Dec --- .../ffmpeg-6.0.1_plugin_for_hw265_dec.patch | 693 ++++++++++++++++++ 1 file changed, 693 insertions(+) create mode 100644 open_source/ffmpeg/hw265dec/ffmpeg-6.0.1_plugin_for_hw265_dec.patch diff --git a/open_source/ffmpeg/hw265dec/ffmpeg-6.0.1_plugin_for_hw265_dec.patch b/open_source/ffmpeg/hw265dec/ffmpeg-6.0.1_plugin_for_hw265_dec.patch new file mode 100644 index 0000000..e5a7e83 --- /dev/null +++ b/open_source/ffmpeg/hw265dec/ffmpeg-6.0.1_plugin_for_hw265_dec.patch @@ -0,0 +1,693 @@ +diff -urpN FFmpeg-n6.0.1/configure FFmpeg-n6.0.1-hw265dec/configure +--- FFmpeg-n6.0.1/configure 2023-11-10 08:00:22.000000000 +0800 ++++ FFmpeg-n6.0.1-hw265dec/configure 2024-03-18 17:14:42.000000000 +0800 +@@ -291,6 +291,7 @@ External library support: + --enable-libwebp enable WebP encoding via libwebp [no] + --enable-libx264 enable H.264 encoding via x264 [no] + --enable-libx265 enable HEVC encoding via x265 [no] ++ --enable-libhw265dec enable HEVC decoding via hw265dec [no] + --enable-libxavs enable AVS encoding via xavs [no] + --enable-libxavs2 enable AVS2 encoding via xavs2 [no] + --enable-libxcb enable X11 grabbing using XCB [autodetect] +@@ -1873,6 +1874,7 @@ EXTERNAL_LIBRARY_LIST=" + openssl + pocketsphinx + vapoursynth ++ libhw265dec + " + + HWACCEL_AUTODETECT_LIBRARY_LIST=" +@@ -3395,6 +3397,7 @@ libx264_encoder_select="atsc_a53" + libx264rgb_encoder_deps="libx264" + libx264rgb_encoder_select="libx264_encoder" + libx265_encoder_deps="libx265" ++libhw265dec_decoder_deps="libhw265dec" + libx265_encoder_select="atsc_a53" + libxavs_encoder_deps="libxavs" + libxavs2_encoder_deps="libxavs2" +@@ -6731,6 +6734,7 @@ enabled libx264 && require_pkg + check_cpp_condition libx262 x264.h "X264_MPEG2" + enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get && + require_cpp_condition libx265 x265.h "X265_BUILD >= 89" ++enabled libhw265dec && require libhw265dec "hwd_api.h" HWD_DecodeStream "-lhw265dec" + enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" + enabled libxavs2 && require_pkg_config libxavs2 "xavs2 >= 1.3.0" "stdint.h xavs2.h" xavs2_api_get + enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore +diff -urpN FFmpeg-n6.0.1/libavcodec/Makefile FFmpeg-n6.0.1-hw265dec/libavcodec/Makefile +--- FFmpeg-n6.0.1/libavcodec/Makefile 2023-11-10 08:00:22.000000000 +0800 ++++ FFmpeg-n6.0.1-hw265dec/libavcodec/Makefile 2024-03-18 17:12:00.000000000 +0800 +@@ -1128,6 +1128,7 @@ OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) + OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o + OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o + OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o ++OBJS-$(CONFIG_LIBHW265DEC_DECODER) += libhw265dec.o + OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o + OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o + OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o +diff -urpN FFmpeg-n6.0.1/libavcodec/allcodecs.c FFmpeg-n6.0.1-hw265dec/libavcodec/allcodecs.c +--- FFmpeg-n6.0.1/libavcodec/allcodecs.c 2023-11-10 08:00:22.000000000 +0800 ++++ FFmpeg-n6.0.1-hw265dec/libavcodec/allcodecs.c 2024-03-18 17:12:57.000000000 +0800 +@@ -160,6 +160,7 @@ extern const FFCodec ff_h264_qsv_decoder + extern const FFCodec ff_h264_rkmpp_decoder; + extern const FFCodec ff_hap_encoder; + extern const FFCodec ff_hap_decoder; ++extern const FFCodec ff_libhw265dec_decoder; + extern const FFCodec ff_hevc_decoder; + extern const FFCodec ff_hevc_qsv_decoder; + extern const FFCodec ff_hevc_rkmpp_decoder; +diff -urpN FFmpeg-n6.0.1/libavcodec/libhw265dec.c FFmpeg-n6.0.1-hw265dec/libavcodec/libhw265dec.c +--- FFmpeg-n6.0.1/libavcodec/libhw265dec.c 1970-01-01 08:00:00.000000000 +0800 ++++ FFmpeg-n6.0.1-hw265dec/libavcodec/libhw265dec.c 2024-03-21 11:16:16.564399800 +0800 +@@ -0,0 +1,632 @@ ++/* ++ * HW265DEC decoder for hevc ++ * copyright (c) 2020-2021 Huawei Technologies Co., Ltd. ++ * ++ * 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 "hwd_api.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "libavutil/internal.h" ++#include "libavutil/common.h" ++#include "libavutil/pixdesc.h" ++#include "libavutil/channel_layout.h" ++#include "libavutil/opt.h" ++#include "libavutil/avutil.h" ++#include "libavutil/imgutils.h" ++#include "avcodec.h" ++#include "internal.h" ++ ++#include "codec_internal.h" ++#include "hevc.h" ++#include "bytestream.h" ++ ++#define PKT_BUF_DEEP 5 ++#define MAX_PKT_BUF_SIZE (1 << PKT_BUF_DEEP) ++#define PKT_QUE_MASK (MAX_PKT_BUF_SIZE - 1) ++ ++typedef struct HW265DecContext { ++ AVClass *class; ++ HWD_Handle handle; ++ HWDCreateParams initParams; ++ int32_t channelID; ++ int32_t picMaxWidth; ++ int32_t picMaxHeight; ++ int32_t maxRefNum; ++ int32_t maxVPSNum; ++ int32_t maxSPSNum; ++ int32_t maxPPSNum; ++ int32_t threadsNum; ++ int32_t bitDepth; ++ ++ AVCodecContext *avctx; ++ ++ AVPacket *buffer_format; ++ uint8_t *extradata; ++ int32_t extradata_size; ++ int32_t extradata_parsed; ++ ++ FILE* file; ++ ++ const uint8_t *data; ++ ++ uint8_t length_size; ++ ++ AVFrame *frame_buffer[MAX_PKT_BUF_SIZE]; ++ volatile uint32_t frame_write_index; ++ volatile uint32_t frame_read_index; ++} HW265DecContext; ++ ++#define PIC_MIN_WIDTH 320 ++#define PIC_MIN_HEIGHT 320 ++#define PIC_MAX_WIDTH 16384 ++#define PIC_MAX_HEIGHT 16384 ++#define PIC_DEFAULT_WIDTH 4096 ++#define PIC_DEFAULT_HEIGHT 2160 ++#define DEFAULT_BIT_DEPTH 8 ++#define MAX_REF_NUM 15 ++#define MAX_VPS_NUM 16 ++#define MAX_SPS_NUM 16 ++#define MAX_PPS_NUM 64 ++#define DEFAULT_THREADS_NUM 4 ++#define MIN_THREADS_NUM 1 ++#define MAX_THREADS_NUM 16 ++ ++#define MIN_HEVCC_LENGTH 23 ++ ++#define OFFSET(x) offsetof(HW265DecContext, x) ++#define VE (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM) ++ ++static const AVOption hw265_dec_options[] = { ++ {"max_width", "pic max width [320, 16384], default 4096", OFFSET(picMaxWidth), AV_OPT_TYPE_INT, {.i64 = 4096}, PIC_MIN_WIDTH, PIC_MAX_WIDTH, VE}, ++ {"max_height", "pic max height [320, 16384], default 2160", OFFSET(picMaxHeight), AV_OPT_TYPE_INT, {.i64 = 2160}, PIC_MIN_HEIGHT, PIC_MAX_HEIGHT, VE}, ++ {"max_ref_num", "pic max ref num [0, 15], default 15", OFFSET(maxRefNum), AV_OPT_TYPE_INT, {.i64 = 15}, 0, MAX_REF_NUM, VE}, ++ {"threads_num", "multi thread num [1, 16], default 4", OFFSET(threadsNum), AV_OPT_TYPE_INT, {.i64 = 0}, 0, MAX_THREADS_NUM, VE}, ++ {"bit_depth", "pic bit depth {8, 10}, default 8", OFFSET(bitDepth), AV_OPT_TYPE_INT, {.i64 = 8}, 8, 10, VE}, ++ {"max_vps_num", "max vps num [1, 16], default 16", OFFSET(maxVPSNum), AV_OPT_TYPE_INT, {.i64 = 16}, 1, MAX_VPS_NUM, VE}, ++ {"max_sps_num", "max sps num [1, 16], default 16", OFFSET(maxSPSNum), AV_OPT_TYPE_INT, {.i64 = 16}, 1, MAX_SPS_NUM, VE}, ++ {"max_pps_num", "max pps num [1, 64], default 64", OFFSET(maxPPSNum), AV_OPT_TYPE_INT, {.i64 = 64}, 1, MAX_PPS_NUM, VE}, ++ { NULL } ++}; ++ ++static const AVClass hw265_decoder_class = { ++ .class_name = "hw265dec", ++ .item_name = av_default_item_name, ++ .option = hw265_dec_options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static void *HW265D_Malloc(uint32_t channel_id, uint32_t size) ++{ ++ return (void *)av_mallocz(size); ++} ++ ++static void HW265D_Free(uint32_t channel_id, void *ptr) ++{ ++ av_freep(&ptr); ++} ++ ++static void HW265D_Log(uint32_t channel_id, HW265VIDEO_ALG_LOG_LEVEL eLevel, int8_t *msg, ...) ++{ ++ va_list arg; ++ int level = AV_LOG_INFO; ++ ++ switch (eLevel) { ++ case HW265VIDEO_ALG_LOG_DEBUG: ++ level = AV_LOG_DEBUG; ++ break; ++ case HW265VIDEO_ALG_LOG_INFO: ++ level = AV_LOG_INFO; ++ break; ++ case HW265VIDEO_ALG_LOG_WARNING: ++ level = AV_LOG_WARNING; ++ break; ++ case HW265VIDEO_ALG_LOG_ERROR: ++ level = AV_LOG_ERROR; ++ break; ++ default: ++ break; ++ } ++ ++ va_start(arg, msg); ++ av_log(NULL, level, msg, arg); ++ va_end(arg); ++} ++ ++static int set_default_value(AVCodecContext *avctx) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ HW265DecContext *ctx = NULL; ++ if (!avctx || !avctx->priv_data) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return ret; ++ } ++ ++ ctx = avctx->priv_data; ++ ctx->frame_read_index = 0; ++ ctx->frame_write_index = 0; ++ ctx->initParams.channelID = 0; ++ ctx->initParams.maxWidth = PIC_DEFAULT_WIDTH; ++ ctx->initParams.maxHeight = PIC_DEFAULT_HEIGHT; ++ ctx->initParams.maxRefNum = MAX_REF_NUM; ++ ctx->initParams.bitDepth = DEFAULT_BIT_DEPTH; ++ ctx->initParams.maxVPSNum = MAX_VPS_NUM; ++ ctx->initParams.maxSPSNum = MAX_SPS_NUM; ++ ctx->initParams.maxPPSNum = MAX_PPS_NUM; ++ ctx->initParams.threadsNum = DEFAULT_THREADS_NUM; ++ ctx->initParams.outputOrder = IH265D_DISPLAY_ORDER; ++ ctx->initParams.mallocFxn = HW265D_Malloc; ++ ctx->initParams.freeFxn = HW265D_Free; ++ ctx->initParams.logFxn = HW265D_Log; ++ ++ return 0; ++} ++ ++static int set_input_value(AVCodecContext *avctx) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ HW265DecContext *ctx = NULL; ++ if (!avctx || !avctx->priv_data) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return ret; ++ } ++ ++ ctx = avctx->priv_data; ++ ctx->initParams.channelID = (ctx->channelID > 0) ? ctx->channelID : ctx->initParams.channelID; ++ ctx->initParams.maxWidth = (ctx->picMaxWidth > 0) ? ctx->picMaxWidth : ctx->initParams.maxWidth; ++ ctx->initParams.maxHeight = (ctx->picMaxHeight > 0) ? ctx->picMaxHeight : ctx->initParams.maxHeight; ++ ctx->initParams.maxRefNum = (ctx->maxRefNum > 0) ? ctx->maxRefNum : ctx->initParams.maxRefNum; ++ ctx->initParams.bitDepth = (ctx->bitDepth > 0) ? ctx->bitDepth : ctx->initParams.bitDepth; ++ ctx->initParams.maxVPSNum = (ctx->maxVPSNum > 0) ? ctx->maxVPSNum : ctx->initParams.maxVPSNum; ++ ctx->initParams.maxSPSNum = (ctx->maxSPSNum > 0) ? ctx->maxSPSNum : ctx->initParams.maxSPSNum; ++ ctx->initParams.maxPPSNum = (ctx->maxPPSNum > 0) ? ctx->maxPPSNum : ctx->initParams.maxPPSNum; ++ if (avctx->thread_count > MAX_THREADS_NUM) { ++ ctx->initParams.threadsNum = MAX_THREADS_NUM; ++ } else if (avctx->thread_count < MIN_THREADS_NUM) { ++ ctx->initParams.threadsNum = MIN_THREADS_NUM; ++ } else { ++ ctx->initParams.threadsNum = avctx->thread_count; ++ } ++ // 濡傛灉鍏ュ弬鏄惧紡璁剧疆浜嗙嚎绋嬫暟锛屽垯瑕嗙洊ffmpeg浼犲叆璁剧疆 ++ if (ctx->threadsNum > 0) { ++ ctx->initParams.threadsNum = ctx->threadsNum; ++ } ++ return 0; ++} ++ ++static av_cold int hw265_decode_close(AVCodecContext *avctx) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ HW265DecContext *ctx = NULL; ++ if (!avctx || !avctx->priv_data) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return ret; ++ } ++ ++ ctx = avctx->priv_data; ++ if (ctx->handle) { ++ HWD_Delete(ctx->handle); ++ } ++ ++ av_packet_free(&ctx->buffer_format); ++ av_freep(&ctx->extradata); ++ ctx->extradata_size = 0; ++ ++ ctx->file = NULL; ++ ++ for (int i = 0; i < MAX_PKT_BUF_SIZE; ++i) { ++ if (ctx->frame_buffer[i]) { ++ av_frame_free(&ctx->frame_buffer[i]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int hevc_extradata_to_annexb(HW265DecContext *ctx) ++{ ++ GetByteContext gb; ++ int length_size, unit_nums, ret; ++ uint8_t *new_extradata = NULL; ++ size_t new_extradata_size = 0; ++ ++ ret = 0; ++ bytestream2_init(&gb, ctx->avctx->extradata, ctx->avctx->extradata_size); ++ bytestream2_skip(&gb, 21); ++ length_size = (bytestream2_get_byte(&gb) & 3) + 1; ++ unit_nums = bytestream2_get_byte(&gb); ++ ++ while (unit_nums-- > 0) { ++ int type = bytestream2_get_byte(&gb) & 0x3f; ++ int cnt = bytestream2_get_be16(&gb); ++ if (type != HEVC_NAL_VPS && type != HEVC_NAL_SPS && type != HEVC_NAL_PPS && ++ type != HEVC_NAL_SEI_PREFIX && type != HEVC_NAL_SEI_SUFFIX) { ++ ret = AVERROR_INVALIDDATA; ++ av_log(ctx, AV_LOG_ERROR, "Extradata nalunit type invalid, type: %d\n", type); ++ goto fail; ++ } ++ while (cnt-- > 0) { ++ int nalu_len = bytestream2_get_be16(&gb); ++ int new_len = nalu_len + new_extradata_size + 4; ++ if (new_len + AV_INPUT_BUFFER_PADDING_SIZE > SIZE_MAX) { ++ ret = AVERROR_INVALIDDATA; ++ av_log(ctx, AV_LOG_ERROR, "Extradata nalunit size invalid, size: %d\n", nalu_len); ++ } ++ ret = av_reallocp(&new_extradata, new_len + AV_INPUT_BUFFER_PADDING_SIZE); ++ if (ret < 0) { ++ av_log(ctx, AV_LOG_ERROR, "Extradata nalunit reallocp fail\n"); ++ goto fail; ++ } ++ ++ AV_WB32(new_extradata + new_extradata_size, 1); ++ bytestream2_get_buffer(&gb, new_extradata + new_extradata_size + 4, nalu_len); ++ new_extradata_size = new_len; ++ memset(new_extradata + new_extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ } ++ } ++ ++ if (new_extradata_size == 0) { ++ av_log(ctx, AV_LOG_WARNING, "Extradata is empty\n"); ++ } ++ ctx->extradata = new_extradata; ++ ctx->extradata_size = new_extradata_size; ++ return length_size; ++ ++ fail: ++ av_freep(&new_extradata); ++ return ret; ++} ++ ++static av_cold int hw265_decode_init(AVCodecContext *avctx) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ HW265DecContext *ctx = NULL; ++ if (!avctx || !avctx->priv_data) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ctx = avctx->priv_data; ++ av_log(ctx, AV_LOG_INFO, "HW265DEC INIT\n"); ++ ++ set_default_value(avctx); ++ set_input_value(avctx); ++ ++ avctx->pix_fmt = AV_PIX_FMT_YUV420P; ++ for (int i = 0; i < MAX_PKT_BUF_SIZE; ++i) { ++ ctx->frame_buffer[i] = av_frame_alloc(); ++ if (!ctx->frame_buffer[i]) { ++ av_log(avctx, AV_LOG_ERROR, "ERROR: av_frame_alloc fail\n"); ++ return AVERROR(EINVAL); ++ } ++ } ++ ++ ret = HWD_Create(&ctx->handle, &ctx->initParams); ++ if (ret != HW265D_OK) { ++ av_log(avctx, AV_LOG_ERROR, "ERROR: HW265DEC create fail\n"); ++ return AVERROR(EINVAL); ++ } ++ ++ ctx->avctx = avctx; ++ ctx->length_size = 0; ++ ctx->extradata_parsed = 0; ++ ctx->buffer_format = av_packet_alloc(); ++ ++ if (ctx->avctx->extradata_size < MIN_HEVCC_LENGTH || ++ AV_RB24(ctx->avctx->extradata) == 1 || ++ AV_RB32(ctx->avctx->extradata) == 1) { ++ } else { ++ ret = hevc_extradata_to_annexb(ctx); ++ if (ret < 0) ++ return ret; ++ ctx->length_size = ret; ++ ctx->extradata_parsed = 1; ++ } ++ ++ return 0; ++} ++ ++static int32_t hw265_split_nalu(uint8_t *pStream, uint32_t streamLen, uint32_t *pFrameLen) ++{ ++ uint32_t i; ++ uint32_t state = 0xFFFFFFFF; ++ uint32_t bFrameStartFound = 0; ++ uint32_t bSliceStartFound = 0; ++ ++ *pFrameLen = 0; ++ if (NULL == pStream || streamLen <= 4) { ++ return -1; ++ } ++ ++ for (i = 0; i < streamLen; ++i) { ++ if ((state & 0xFFFFFF7E) >= 0x100 && (state & 0xFFFFFF7E) <= 0x13E) { ++ if (bFrameStartFound == 1 || bSliceStartFound == 1) { ++ if ((pStream[i + 1] >> 7) == 1) { ++ *pFrameLen = i - 4; ++ return 0; ++ } ++ } else { ++ bSliceStartFound = 1; ++ } ++ } ++ ++ if ((state & 0xFFFFFF7E) == 0x140 || (state & 0xFFFFFF7E) == 0x142 || (state & 0xFFFFFF7E) == 0x144) { ++ if (bSliceStartFound == 1) { ++ bSliceStartFound = 1; ++ } else if (bFrameStartFound == 1) { ++ *pFrameLen = i - 4; ++ return 0; ++ } else { ++ bFrameStartFound = 1; ++ } ++ } ++ ++ state = (state << 8) | pStream[i]; ++ } ++ ++ *pFrameLen = i; ++ ++ return -1; ++} ++ ++static int popFrame(AVCodecContext *avctx, AVFrame *frame) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ ++ HW265DecContext *ctx = NULL; ++ uint32_t frame_read_index = 0; ++ if (!avctx || !avctx->priv_data) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return ret; ++ } ++ ++ ctx = avctx->priv_data; ++ if (ctx->frame_write_index == ctx->frame_read_index) { ++ return -1; ++ } ++ frame_read_index = ctx->frame_read_index; ++ ++ if (atomic_fetch_add_explicit(&ctx->frame_read_index, 1, memory_order_acq_rel) == frame_read_index) { ++ av_frame_move_ref(frame, ctx->frame_buffer[frame_read_index & PKT_QUE_MASK]); ++ if (ctx->file) { ++ for (int i = 0; i < frame->height; i++) { ++ fwrite(frame->extended_data[0] + i * frame->linesize[0], 1, frame->width, ctx->file); ++ } ++ for (int i = 0; i < frame->height / 2; i++) { ++ fwrite(frame->extended_data[1] + i * frame->linesize[1], 1, frame->width/2, ctx->file); ++ } ++ for (int i = 0; i < frame->height / 2; i++) { ++ fwrite(frame->extended_data[2] + i * frame->linesize[2], 1, frame->width/2, ctx->file); ++ } ++ fflush(ctx->file); ++ } ++ } ++ ++ return 0; ++} ++ ++static int pushFrame(AVCodecContext *avctx, HWDOutputParams *stOutArgs) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ ++ HW265DecContext *ctx = NULL; ++ uint32_t frame_write_index = 0; ++ if (!avctx || !avctx->priv_data) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return ret; ++ } ++ ++ ctx = avctx->priv_data; ++ frame_write_index = ctx->frame_write_index; ++ if (atomic_fetch_add_explicit(&ctx->frame_write_index, 1, memory_order_acq_rel) == frame_write_index) { ++ AVFrame *frame = ctx->frame_buffer[frame_write_index & PKT_QUE_MASK]; ++ if (frame->format == -1) { ++ avctx->pix_fmt=AV_PIX_FMT_YUV420P; ++ avctx->width=stOutArgs->decWidth; ++ avctx->height=stOutArgs->decHeight; ++ frame->format = AV_PIX_FMT_YUV420P; ++ frame->width = stOutArgs->decWidth; ++ frame->height = stOutArgs->decHeight; ++ av_frame_get_buffer(frame, 0); ++ } ++ frame->extended_data[0] = frame->data[0] = stOutArgs->outYUVData[0]; ++ frame->extended_data[1] = frame->data[1] = stOutArgs->outYUVData[1]; ++ frame->extended_data[2] = frame->data[2] = stOutArgs->outYUVData[2]; ++ frame->linesize[0] = stOutArgs->yStride; ++ frame->linesize[1] = stOutArgs->uvStride; ++ frame->linesize[2] = stOutArgs->uvStride; ++ frame->linesize[3] = 1; ++ frame->key_frame = 0; ++ switch (stOutArgs->eFrameType) { ++ case IH265D_FRAME_I: ++ frame->pict_type = AV_PICTURE_TYPE_I; ++ frame->key_frame = 1; ++ break; ++ case IH265D_FRAME_P: ++ frame->pict_type = AV_PICTURE_TYPE_P; ++ break; ++ case IH265D_FRAME_B: ++ frame->pict_type = AV_PICTURE_TYPE_B; ++ break; ++ default: ++ frame->pict_type = AV_PICTURE_TYPE_NONE; ++ break; ++ } ++ ++ frame->pkt_pos = avctx->internal->last_pkt_props->pos; ++ frame->duration = avctx->internal->last_pkt_props->duration; ++ } ++ ++ return 0; ++} ++ ++static int mp4toannexb_filter(HW265DecContext *ctx, AVPacket *avpkt, uint8_t **pStream, uint32_t *length) ++{ ++ int ret = 0; ++ ++ if (ctx->length_size && ctx->extradata_parsed) { ++ GetByteContext gb; ++ ++ int got_irap = 0; ++ int i = 0; ++ int head_len = 0; ++ ++ bytestream2_init(&gb, avpkt->data, avpkt->size); ++ av_packet_unref(ctx->buffer_format); ++ ++ while (bytestream2_get_bytes_left(&gb)) { ++ uint32_t nalu_size = 0; ++ int nalu_type; ++ int is_irap, add_extradata, extra_size, prev_size; ++ ++ for (i = 0; i < ctx->length_size; i++) { ++ nalu_size = (nalu_size << 8) | bytestream2_get_byte(&gb); ++ } ++ ++ nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; ++ ++ /* prepend extradata to IRAP frames */ ++ is_irap = nalu_type >= 16 && nalu_type <= 23; ++ add_extradata = is_irap && !got_irap; ++ extra_size = add_extradata * ctx->extradata_size; ++ got_irap |= is_irap; ++ ++ if (SIZE_MAX - nalu_size < 4 || ++ SIZE_MAX - 4 - nalu_size < extra_size) { ++ ret = AVERROR_INVALIDDATA; ++ return -1; ++ } ++ ++ prev_size = ctx->buffer_format->size; ++ head_len = is_irap ? 4 : (nalu_type > 31 ? 4 : 3); ++ ++ ret = av_grow_packet(ctx->buffer_format, 4 + nalu_size + extra_size); ++ if (ret < 0) { ++ return -1; ++ } ++ ++ if (add_extradata) { ++ memcpy(ctx->buffer_format->data + prev_size, ctx->extradata, extra_size); ++ } ++ if (head_len == 4) { ++ AV_WB32(ctx->buffer_format->data + prev_size + extra_size, 1); ++ } else { ++ AV_WB24(ctx->buffer_format->data + prev_size + extra_size, 1); ++ } ++ bytestream2_get_buffer(&gb, ctx->buffer_format->data + prev_size + head_len + extra_size, nalu_size); ++ } ++ ++ av_packet_copy_props(ctx->buffer_format, avpkt); ++ *pStream = ctx->buffer_format->data; ++ *length = ctx->buffer_format->size; ++ } ++ ++ return 0; ++} ++ ++static int hw265_decode_frame(AVCodecContext *avctx, AVFrame *data, int *got_output, AVPacket *avpkt) ++{ ++ int ret = AVERROR_INVALIDDATA; ++ ++ HW265DecContext *ctx = NULL; ++ uint8_t *streamData = NULL; ++ uint32_t isStreamEnd = 0; ++ uint32_t length = 0; ++ HWDInputParams stInArgs = { 0 }; ++ HWDOutputParams stOutArgs = { 0 }; ++ if (!avctx || !avctx->priv_data || !avpkt) { ++ av_log(avctx, AV_LOG_ERROR, "null object\n"); ++ return ret; ++ } ++ ++ ctx = avctx->priv_data; ++ streamData = avpkt->data; ++ length = avpkt->size; ++ *got_output = 0; ++ ret = avpkt->size; ++ ret = mp4toannexb_filter(ctx, avpkt, &streamData, &length); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ while (!isStreamEnd) ++ { ++ int32_t naluLen; ++ hw265_split_nalu(streamData, length, &naluLen); ++ ++ stInArgs.decodeMode = IH265D_DECODE; ++ stInArgs.streamData = streamData; ++ stInArgs.streamLen = naluLen; ++ ++ if (length == 0) { ++ stInArgs.decodeMode = IH265D_DECODE_END; ++ } ++ ++ if (naluLen == 0 && avpkt->size != 0) { ++ break; ++ } ++ ++ streamData += naluLen; ++ length -= naluLen; ++ stOutArgs.eDecodeStatus = -1; ++ stOutArgs.bytsConsumed = 0; ++ ++ while (stOutArgs.eDecodeStatus != IH265D_NEED_MORE_BITS) { ++ if (stOutArgs.eDecodeStatus == IH265D_NO_PICTURE) { ++ isStreamEnd = 1; ++ break; ++ } ++ ++ if (stOutArgs.eDecodeStatus == IH265D_GETDISPLAY) { ++ pushFrame(avctx, &stOutArgs); ++ } ++ ++ stInArgs.streamData += stOutArgs.bytsConsumed; ++ stInArgs.streamLen -= stOutArgs.bytsConsumed; ++ ++ ret = HWD_DecodeStream(ctx->handle, &stInArgs, &stOutArgs); ++ if ((ret != HW265D_OK) && (ret != IH265D_NEED_MORE_BITS)) { ++ if (0 == length) { ++ isStreamEnd = 1; ++ } ++ break; ++ } ++ } ++ } ++ ++ if (!popFrame(avctx, data)) { ++ *got_output = 1; ++ } ++ return avpkt->size; ++} ++ ++const FFCodec ff_libhw265dec_decoder = { ++ .p.name = "hw265dec", ++ CODEC_LONG_NAME("hw265dec H.265/HEVC decoder"), ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_HEVC, ++ .priv_data_size = sizeof(HW265DecContext), ++ .p.priv_class = &hw265_decoder_class, ++ .init = hw265_decode_init, ++ .close = hw265_decode_close, ++ FF_CODEC_DECODE_CB(hw265_decode_frame), ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS, ++};