一 都说android集成了libhevc用来做h265软解码,因为性能比较好。我自己在x86上测试了一下,估计是libhevc 实现的x86 SIMD不太好,速度只有ffmpeg里面openhec的20%左右。

二 先在ffmpeg里面实现wrapper给android端同学用用。

三 libhevc全都是操作结构体的方式调用的,其实用起来不是很方便。尤其是出错了,也不知道啥原因,需要一步步debug。 libhevc自己的demo,是结合了display的,不能作为参考,因为集成到ffmpeg里面也不需要display。

四 libhevc解码步骤

4.1 创建对象

4.2 设置解码核个数

 4.3 设置CPU类型

这里,因为我要用在手机上,所以默认设置的ARM_NEON

4.4 解码器设置为解码参数头模式

 4.5 解码参数头,vps,sps,pps

4.6 把解码器设置为解码帧模式

 4.7 解码视频帧

 总结:大概就是分上面7个步骤,值得注意的时候,有时候输入的视频帧是hvcc格式的,有时候是annexb格式的。但是libhevc只能解码annexb格式的,所以需要转换下。另外解码出来的视频帧是yuv420sp_uv格式的,我们常用的是yuv420p格式的,这个我们需要转换下。

上代码:

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

#include "libavutil/avassert.h"
#include "libavutil/cpu.h"
#include "libavutil/film_grain_params.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"

#include "hevc_parse.h"
#include "avcodec.h"
#include "bytestream.h"
#include "codec_internal.h"
#include "decode.h"
#include "internal.h"
#include "ihevc_typedefs.h"
#include "iv.h"
#include "ivd.h"
#include "ihevcd_cxa.h"
#include "ithread.h"
#include "ihevcd_error.h"
#include "bsf.h"

#define ALIGN8(x) ((((x) + 7) >> 3) << 3)
#define NUM_DISPLAY_BUFFERS 4
#define DEFAULT_FPS         30

#define ENABLE_DEGRADE 0
#define MAX_DISP_BUFFERS    64
#define EXTRA_DISP_BUFFERS  0
#define STRLENGTH 1000

#define ADAPTIVE_TEST
#define ADAPTIVE_MAX_WD 8192
#define ADAPTIVE_MAX_HT 4096
//#define TEST_FLUSH
#define FLUSH_FRM_CNT 100

#define PEAK_WINDOW_SIZE            8
#define DEFAULT_SHARE_DISPLAY_BUF   0
#define STRIDE                      0
#define DEFAULT_NUM_CORES           2

#define DUMP_SINGLE_BUF 0
#define IV_ISFATALERROR(x)         (((x) >> IVD_FATALERROR) & 0x1)

#define ivd_cxa_api_function        ihevcd_cxa_api_function
#define INIT_INVALID_PTS  (-500000)
typedef struct
{
    UWORD32 u4_piclen_flag;
    UWORD32 u4_file_save_flag;
    UWORD32 u4_chksum_save_flag;
    IV_COLOR_FORMAT_T e_output_chroma_format;
    IVD_ARCH_T e_arch;
    IVD_SOC_T e_soc;
    UWORD32 dump_q_rd_idx;
    UWORD32 dump_q_wr_idx;
    WORD32  disp_q_wr_idx;
    WORD32  disp_q_rd_idx;

    void *cocodec_obj;
    UWORD32 share_disp_buf;
    UWORD32 num_disp_buf;
    UWORD32 b_pic_present;
    WORD32 i4_degrade_type;
    WORD32 i4_degrade_pics;
    UWORD32 u4_num_cores;
    UWORD32 disp_delay;
    WORD32 trace_enable;
    CHAR ac_trace_fname[STRLENGTH];
    CHAR ac_piclen_fname[STRLENGTH];
    CHAR ac_ip_fname[STRLENGTH];
    CHAR ac_op_fname[STRLENGTH];
    CHAR ac_op_chksum_fname[STRLENGTH];
    ivd_out_bufdesc_t s_disp_buffers[MAX_DISP_BUFFERS];
    iv_yuv_buf_t s_disp_frm_queue[MAX_DISP_BUFFERS];
    UWORD32 s_disp_frm_id_queue[MAX_DISP_BUFFERS];
    UWORD32 loopback;
    UWORD32 display;
    UWORD32 full_screen;
    UWORD32 fps;
    UWORD32 max_wd;
    UWORD32 max_ht;
    UWORD32 max_level;

    UWORD32 u4_strd;

    /* For signalling to display thread */
    UWORD32 u4_pic_wd;
    UWORD32 u4_pic_ht;

    /* For IOS diplay */
    WORD32 i4_screen_wd;
    WORD32 i4_screen_ht;

    //UWORD32 u4_output_present;
    WORD32  quit;
    WORD32  paused;
    WORD32  last_gebuf_index;    

    void *pv_disp_ctx;
    void *display_thread_handle;
    WORD32 display_thread_created;
    volatile WORD32 display_init_done;
    volatile WORD32 display_deinit_flag;

    IV_COLOR_FORMAT_T (*get_color_fmt)(void);
    UWORD32 (*get_stride)(void);
} vid_dec_ctx_t;

typedef struct LibhevcdecContext {
    AVClass *class;
    /* This packet coincides with AVCodecInternal.in_pkt
     * and if not owned by us. */
    AVBufferPool *pool;
    int pool_size;
    int tile_threads;
    int num_cores;
    int apply_grain;
    char *cpu_simd;
    int operating_point;
    int all_layers;
    vid_dec_ctx_t s_app_ctx;
    int inited;
    ivd_out_bufdesc_t *ps_out_buf;
    const AVBitStreamFilter *hevcbsfc;
    AVBSFContext *bsf_context;
    int last_max_timestamp;
    int last_duration;
} LibhevcdecContext;

#define HEVCDEC_PIXEL_LAYOUT_I400 0
#define HEVCDEC_PIXEL_LAYOUT_I420 1
#define HEVCDEC_PIXEL_LAYOUT_I422 2
#define HEVCDEC_PIXEL_LAYOUT_I444 3
static const uint8_t libhevc_startcode[4] = {0x00, 0x00, 0x00, 0x01};
static const enum AVPixelFormat pix_fmt[][3] = {
    [HEVCDEC_PIXEL_LAYOUT_I400] = { AV_PIX_FMT_GRAY8,   AV_PIX_FMT_GRAY10,    AV_PIX_FMT_GRAY12 },
    [HEVCDEC_PIXEL_LAYOUT_I420] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P12 },
    [HEVCDEC_PIXEL_LAYOUT_I422] = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12 },
    [HEVCDEC_PIXEL_LAYOUT_I444] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12 },
};

static const enum AVPixelFormat pix_fmt_rgb[3] = {
    AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
};


static UWORD32 default_get_stride(void)
{
    return 0;
}

static IV_COLOR_FORMAT_T default_get_color_fmt(void)
{
    return IV_YUV_420P;
}

static void * _aligned_malloc(int32_t size, int32_t alignment)
{
    int32_t alignsize = (size + alignment - 1)/alignment * alignment;
    return malloc(alignsize);
}

static void _aligned_free(void *pv_buf)
{
    if (pv_buf) {
        free(pv_buf);
    }
}

static void *ihevca_aligned_malloc(void *pv_ctxt, WORD32 alignment, WORD32 i4_size)
{
    (void)pv_ctxt;
    return (void *)_aligned_malloc(i4_size, alignment);
}

static void ihevca_aligned_free(void *pv_ctxt, void *pv_buf)
{
    (void)pv_ctxt;
    _aligned_free(pv_buf);
    return;
}

static int libhevcdec_init_bsf(AVCodecContext *c)
{
    LibhevcdecContext *libhevc = (LibhevcdecContext*)c->priv_data;	
    /*
     *init hevc bitstream filter
     * */
    libhevc->hevcbsfc = av_bsf_get_by_name("hevc_mp4toannexb");
    if (libhevc->hevcbsfc == NULL) {
        av_log(c, AV_LOG_ERROR, "libhevc av_bitstream_filter_init  failed.");
        return -4;
    }
    if (av_bsf_alloc(libhevc->hevcbsfc, &libhevc->bsf_context) != 0) {
        av_log(c, AV_LOG_ERROR, "libhevc av_bsf_alloc  failed.");
        return -5;
    }

    if (avcodec_parameters_from_context(libhevc->bsf_context->par_in, c) != 0) {
        av_log(c, AV_LOG_ERROR, "libhevc avcodec_parameters_from_context  failed.");
        return -6;
    }
    libhevc->bsf_context->time_base_in = c->time_base;
    av_bsf_init(libhevc->bsf_context);
    return 0;
}

static av_cold int libhevcdec_init(AVCodecContext *c)
{
    LibhevcdecContext *libhevc = (LibhevcdecContext*)c->priv_data;
/*
 *    int pool_size;
    int tile_threads;
    int num_cores;
    int apply_grain;
    int operating_point;
    int all_layers;
 * */
    int ret;
    strcpy(libhevc->s_app_ctx.ac_ip_fname, "\0");
    libhevc->s_app_ctx.dump_q_wr_idx = 0;
    libhevc->s_app_ctx.dump_q_rd_idx = 0;
    libhevc->s_app_ctx.display_thread_created = 0;
    libhevc->s_app_ctx.disp_q_wr_idx = 0;
    libhevc->s_app_ctx.disp_q_rd_idx = 0;
    libhevc->s_app_ctx.disp_delay = 0;
    libhevc->s_app_ctx.loopback = 0;
    libhevc->s_app_ctx.display = 0;
    libhevc->s_app_ctx.full_screen = 0;
    libhevc->s_app_ctx.u4_piclen_flag = 0;
    libhevc->s_app_ctx.fps = DEFAULT_FPS;
    libhevc->s_app_ctx.share_disp_buf = 0;//DEFAULT_SHARE_DISPLAY_BUF;
    libhevc->s_app_ctx.u4_num_cores = DEFAULT_NUM_CORES;
    libhevc->s_app_ctx.i4_degrade_type = 0;
    libhevc->s_app_ctx.i4_degrade_pics = 0;
    libhevc->s_app_ctx.e_arch = ARCH_ARM_A9Q;
    libhevc->s_app_ctx.e_soc = SOC_GENERIC;
    libhevc->s_app_ctx.u4_strd = STRIDE;
    libhevc->s_app_ctx.display_thread_handle           = malloc(ithread_get_handle_size());
    libhevc->s_app_ctx.quit          = 0;
    libhevc->s_app_ctx.paused        = 0;
    libhevc->s_app_ctx.get_stride = &default_get_stride;
    libhevc->s_app_ctx.get_color_fmt = &default_get_color_fmt;
    libhevc->s_app_ctx.display_deinit_flag = 0;
    libhevc->s_app_ctx.e_output_chroma_format = IV_YUV_420SP_UV;
    libhevc->inited = 0;
    libhevc->bsf_context = NULL;
    libhevc->last_max_timestamp = INIT_INVALID_PTS;
    libhevc->last_duration = 40;//default 25fps
    libhevc->ps_out_buf = (ivd_out_bufdesc_t *)malloc(sizeof(ivd_out_bufdesc_t));
    memset(libhevc->ps_out_buf, 0x0, sizeof(ivd_out_bufdesc_t));
    libhevc->ps_out_buf->u4_num_bufs = 3;
    /*
     *create decode instance 
     * */
    ihevcd_cxa_create_ip_t s_create_ip;
    ihevcd_cxa_create_op_t s_create_op;
    void *fxns = &ivd_cxa_api_function;

    s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
    s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = libhevc->s_app_ctx.share_disp_buf;
    s_create_ip.s_ivd_create_ip_t.e_output_format = (IV_COLOR_FORMAT_T)libhevc->s_app_ctx.e_output_chroma_format;
    s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ihevca_aligned_malloc;
    s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ihevca_aligned_free;
    s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
    s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ihevcd_cxa_create_ip_t);
    s_create_op.s_ivd_create_op_t.u4_size = sizeof(ihevcd_cxa_create_op_t);
    ret = ivd_cxa_api_function(NULL, (void *)&s_create_ip,
                                       (void *)&s_create_op);
    if (ret != IV_SUCCESS) {
        av_log(c, AV_LOG_ERROR, "libhevc decoder open created failed.");        
	return -1;
    }
    iv_obj_t *codec_obj = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    codec_obj->pv_fxns = fxns;
    codec_obj->u4_size = sizeof(iv_obj_t);
    libhevc->s_app_ctx.cocodec_obj = codec_obj; //set code object here ############################
    /*
     * set num of cores
    */
    ihevcd_cxa_ctl_set_num_cores_ip_t s_ctl_set_cores_ip;
    ihevcd_cxa_ctl_set_num_cores_op_t s_ctl_set_cores_op;

    s_ctl_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_set_cores_ip.e_sub_cmd = (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES;
    s_ctl_set_cores_ip.u4_num_cores = libhevc->s_app_ctx.u4_num_cores;
    s_ctl_set_cores_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_ip_t);
    s_ctl_set_cores_op.u4_size = sizeof(ihevcd_cxa_ctl_set_num_cores_op_t);
    ret = ivd_cxa_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_set_cores_ip,
                                   (void *)&s_ctl_set_cores_op);
    if (ret != IV_SUCCESS) {
        av_log(c, AV_LOG_ERROR, "libhevc decoder set cores failed.");     
        return -2; 
    }
    /*
     *set processor type
     * */
    ihevcd_cxa_ctl_set_processor_ip_t s_ctl_set_num_processor_ip;
    ihevcd_cxa_ctl_set_processor_op_t s_ctl_set_num_processor_op;

    s_ctl_set_num_processor_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_set_num_processor_ip.e_sub_cmd = (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_PROCESSOR;
    s_ctl_set_num_processor_ip.u4_arch = libhevc->s_app_ctx.e_arch;
    s_ctl_set_num_processor_ip.u4_soc = libhevc->s_app_ctx.e_soc;
    s_ctl_set_num_processor_ip.u4_size = sizeof(ihevcd_cxa_ctl_set_processor_ip_t);
    s_ctl_set_num_processor_op.u4_size = sizeof(ihevcd_cxa_ctl_set_processor_op_t);

    ret = ivd_cxa_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_set_num_processor_ip,
                                   (void *)&s_ctl_set_num_processor_op);
    if (ret != IV_SUCCESS) {
        av_log(c, AV_LOG_ERROR, "libhevc decoder set processor type failed.");
        return -3;	
    }

    return 0;	
}

static void libhevcdec_flush(AVCodecContext *c)
{
#if 0
    Libdav1dContext *dav1d = c->priv_data;

    dav1d_data_unref(&dav1d->data);
    dav1d_flush(dav1d->c);
#endif
}



static int libhevcdec_fill_frame_withbuf(AVCodecContext *c, AVFrame *frame, ivd_video_decode_op_t *s_video_decode_frame_op, 
		ivd_video_decode_ip_t *s_video_decode_frame_ip)
{
    LibhevcdecContext *libhevc = (LibhevcdecContext*)c->priv_data;	
    frame->width = c->width;
    frame->height = c->height;
    frame->format = AV_PIX_FMT_YUV420P;
    if (libhevc->last_max_timestamp == INIT_INVALID_PTS) {
        libhevc->last_max_timestamp = s_video_decode_frame_op->u4_ts;
    } else {
        if (libhevc->last_max_timestamp >= s_video_decode_frame_op->u4_ts
			|| (s_video_decode_frame_op->u4_ts - libhevc->last_max_timestamp < libhevc->last_duration)) {
	    libhevc->last_max_timestamp += libhevc->last_duration;
	} else {
	    libhevc->last_max_timestamp = s_video_decode_frame_op->u4_ts;
	} 
    }
    frame->pts = libhevc->last_max_timestamp;   
    frame->pkt_dts = libhevc->last_max_timestamp;
    if (av_frame_get_buffer(frame, 16) != 0) {
        av_log(c, AV_LOG_ERROR, "decode get AVFrame buffer failed.");    
        return -14;
    }
    if (s_video_decode_frame_op->e_pic_type == IV_I_FRAME 
		    || s_video_decode_frame_op->e_pic_type == IV_IDR_FRAME) {
        frame->pict_type = AV_PICTURE_TYPE_I;
	frame->key_frame = 1;
    } else if (s_video_decode_frame_op->e_pic_type == IV_P_FRAME ||
		    s_video_decode_frame_op->e_pic_type == IV_IP_FRAME ||
		    s_video_decode_frame_op->e_pic_type == IV_PP_FRAME) {
        frame->pict_type = AV_PICTURE_TYPE_P;
    } else {
        frame->pict_type = AV_PICTURE_TYPE_B;
    }

    if (s_video_decode_frame_op->e_output_format == IV_YUV_420P) {
        /*
	 *copy y
	 * */
	for (int i = 0; i < c->height; i++) {
	    UWORD8 *ybuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_y_buf;
            memcpy(frame->data[0] + i * frame->linesize[0], ybuf + i * s_video_decode_frame_op->s_disp_frm_buf.u4_y_strd, c->width);
	}
	/*
	 *copy u
	 * */
	for (int i = 0; i < c->height/2; i++) {
            UWORD8 *ubuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_u_buf;		
	    UWORD8 *vbuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_v_buf;
	    memcpy(frame->data[1] + i * frame->linesize[1], ubuf + i * s_video_decode_frame_op->s_disp_frm_buf.u4_u_strd, c->width/2);
	    memcpy(frame->data[2] + i * frame->linesize[2], vbuf + i * s_video_decode_frame_op->s_disp_frm_buf.u4_v_strd, c->width/2);
	}
    } else if (s_video_decode_frame_op->e_output_format == IV_YUV_420SP_UV) {
        /*
         *copy y
         * */
        for (int i = 0; i < c->height; i++) {
            UWORD8 *ybuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_y_buf;		
            memcpy(frame->data[0] + i * frame->linesize[0], (uint8_t*)ybuf + i * s_video_decode_frame_op->s_disp_frm_buf.u4_y_strd, c->width);
        }
        /*
         *copy u v
         * */
	for (int i = 0; i < c->height/2; i++) {
            for (int j = 0; j < c->width/2; j++) {
		UWORD8 *ubuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_u_buf;    
		int index = i * s_video_decode_frame_op->s_disp_frm_buf.u4_u_strd + j * 2;
	        frame->data[1][i * frame->linesize[1] + j] = ubuf[index];
		frame->data[2][i * frame->linesize[2] + j] = ubuf[index + 1];
	    }
	}
        
    } else if (s_video_decode_frame_op->e_output_format == IV_YUV_420SP_VU) {
        /*
         *copy y
         * */
        for (int i = 0; i < c->height; i++) {
	    UWORD8 *ybuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_y_buf;	
            memcpy(frame->data[0] + i * frame->linesize[0], ybuf + i * s_video_decode_frame_op->s_disp_frm_buf.u4_y_strd, c->width);
        }
        /*
         *copy u v
         * */
        for (int i = 0; i < c->height/2; i++) {
            for (int j = 0; j < c->width/2; j++) {
		UWORD8 *ubuf = (UWORD8*)s_video_decode_frame_op->s_disp_frm_buf.pv_u_buf;
                int index = i * s_video_decode_frame_op->s_disp_frm_buf.u4_u_strd + j * 2;
                frame->data[2][i * frame->linesize[2] + j] = ubuf[index];
                frame->data[1][i * frame->linesize[1] + j] = ubuf[index + 1];
            }
        }
    }

    return 0;
}

static uint8_t *writebytes(uint8_t *dst, const uint8_t *src, int len)
{
    memcpy(dst, src, len);
    return dst + len;
}

static int libhevcdec_hvcc2annexb(AVCodecContext *c, AVPacket *pkt)
{
    LibhevcdecContext *hevcdec = (LibhevcdecContext *)c->priv_data;  	
    if (av_bsf_send_packet(hevcdec->bsf_context, pkt) < 0){
	av_log(c, AV_LOG_ERROR, "av_bsf_send_packet faile \n");
	return -1;
    }
    if (av_bsf_receive_packet(hevcdec->bsf_context, pkt) < 0) {
	av_log(c, AV_LOG_ERROR, "av_bsf_receive_packet faile \n");
	return -2;
    }
    return 0;
}

static int libhevcdec_make_codechead(AVCodecContext *c, uint8_t **buf)
{
#define MAX_PADDING (256)
    int outlen = c->extradata_size + MAX_PADDING;
    uint8_t *outbuf = (uint8_t*)malloc(outlen);
    uint8_t *tmp = outbuf;
    if (outbuf == NULL) {
        av_log(c, AV_LOG_ERROR, "alloc codec head mem failed..");
	return -1;
    }    
    HEVCParamSets ps;
    HEVCSEI sei;
    memset(&ps, 0x0, sizeof(HEVCParamSets));
    memset(&sei, 0x0, sizeof(HEVCSEI));
    int is_nalff = 0;
    int nal_length_size = 0;
    int res = ff_hevc_decode_extradata(c->extradata, c->extradata_size, &ps, &sei, &is_nalff, &nal_length_size, 0, 0, c);
    if (res != 0) {
        av_log(c, AV_LOG_ERROR, "parse extra data failed.");
        ff_hevc_ps_uninit(&ps);
        return -3;
    }
    for (int i = 0; i < HEVC_MAX_VPS_COUNT; i++) {
        if (ps.vps_list[i]) {
            HEVCVPS *vps = (HEVCVPS *)ps.vps_list[i]->data;
	    tmp = writebytes(tmp, libhevc_startcode, 4);
            tmp = writebytes(tmp, vps->data, vps->data_size);  	    
	}
    }
    for (int i = 0; i < HEVC_MAX_SPS_COUNT; i++) {
        if (ps.sps_list[i]) {
	    HEVCSPS *sps = (HEVCSPS *)ps.sps_list[i]->data;
	    tmp = writebytes(tmp, libhevc_startcode, 4);
            tmp = writebytes(tmp, sps->data, sps->data_size);
	}
    }

    for (int i = 0; i < HEVC_MAX_PPS_COUNT; i++) {
        if (ps.pps_list[i]) {
            HEVCPPS *pps = (HEVCPPS *)ps.pps_list[i]->data;
            tmp = writebytes(tmp, libhevc_startcode, 4);
            tmp = writebytes(tmp, pps->data, pps->data_size);
        }
    }
    ff_hevc_ps_uninit(&ps);
    *buf = outbuf;
    return tmp - outbuf;
}

static int libhevcdec_receive_frame(AVCodecContext *c, AVFrame *frame)
{
    LibhevcdecContext *hevcdec = (LibhevcdecContext *)c->priv_data;
    uint8_t *disp_outbuf = NULL;
    int outlen = 0;
    int cur_dts = 0;
    AVPacket pkt = { 0 };
    int res = ff_decode_get_packet(c, &pkt);
    if (res < 0 && res != AVERROR_EOF)
       return res;
#define FAIL(value) \
    {\
        pkt.buf = NULL; \
        av_packet_unref(&pkt); \
    	return value; \
    }\
(void)0    
#define SUCCESS() FAIL(0)
    if (pkt.size) {	
        cur_dts = pkt.pts;
	if (pkt.duration > 0) {
	    hevcdec->last_duration = pkt.duration;
	}
	if (!hevcdec->inited) {
	    /*
	     *set into decoder header mode
	     * */
	    ivd_ctl_set_config_ip_t s_ctl_ip;
            ivd_ctl_set_config_op_t s_ctl_op;
            s_ctl_ip.u4_disp_wd = 0;
            s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
            s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
            s_ctl_ip.e_vid_dec_mode = IVD_DECODE_HEADER;
            s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
            s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
            s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
            s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
            res = ivd_cxa_api_function((iv_obj_t*)hevcdec->s_app_ctx.cocodec_obj, (void *)&s_ctl_ip,
                                       (void *)&s_ctl_op);
            if (res != IV_SUCCESS) {
	        av_log(c, AV_LOG_ERROR, "set decode header mode failed.");
		FAIL(-2);
	    }	    
            /*
	     * try deocde header
	     * */
#if 1
            uint8_t *headbuf = pkt.data;
	    uint8_t headlen = pkt.size;
	    uint8_t *codechead = NULL;
	    if (c->extradata && c->extradata_size > 0) {
		res = libhevcdec_make_codechead(c, &codechead);
	        if (res < 0) {
		    av_log(c, AV_LOG_ERROR, "parse codec head failed.");
	            if (codechead) av_free(codechead);
		    FAIL(-10);
		}
                headbuf = codechead;
		headlen = res;
	    }
#endif
	    ivd_video_decode_ip_t s_video_decode_ip;
            ivd_video_decode_op_t s_video_decode_op;
	    s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
            s_video_decode_ip.u4_ts = pkt.pts;
            s_video_decode_ip.pv_stream_buffer = headbuf;
            s_video_decode_ip.u4_num_Bytes = headlen;
            s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t);
            s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t);

            /*****************************************************************************/
            /*   API Call: Header Decode                                                  */
            /*****************************************************************************/
            res = ihevcd_cxa_api_function((iv_obj_t *)hevcdec->s_app_ctx.cocodec_obj, (void *)&s_video_decode_ip,
                                       (void *)&s_video_decode_op);
	    if (codechead) av_free(codechead);

	    if (res != IV_SUCCESS) {
	        av_log(c, AV_LOG_ERROR, "decode header failed.");
		FAIL(-3);
	    }
	    c->width = s_video_decode_op.u4_pic_wd;
	    c->height = s_video_decode_op.u4_pic_ht;
            c->codec_type = AVMEDIA_TYPE_VIDEO;
	    if (libhevcdec_init_bsf(c) != 0) {
	        av_log(c, AV_LOG_ERROR, "libhevcdec_init_bsf failed.");
                FAIL(-13);
	    }
        
	    if (libhevcdec_hvcc2annexb(c, &pkt) != 0) {
                av_log(c, AV_LOG_ERROR, "set decode header mode failed.");
                FAIL(-1);
            }
            cur_dts = pkt.dts;

#define AlignTo(value, align) \
	    ((value + align - 1)/align * align)
	    outlen = AlignTo(c->width, 64) * AlignTo(c->height, 64) * 3;
            hevcdec->ps_out_buf->u4_min_out_buf_size[0] = hevcdec->ps_out_buf->u4_min_out_buf_size[1] = 
            hevcdec->ps_out_buf->u4_min_out_buf_size[2] = AlignTo(c->width, 64) * AlignTo(c->height, 64);
	    
#if 1
	    /*
	     *set frame out mode
	     * */
            ivd_ctl_set_config_ip_t s_ctl_decode_ip;
            ivd_ctl_set_config_op_t s_ctl_decode_op;
            s_ctl_decode_ip.u4_disp_wd = 0;
            s_ctl_decode_ip.e_frm_skip_mode = IVD_SKIP_NONE;
            s_ctl_decode_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
            s_ctl_decode_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
            s_ctl_decode_ip.e_cmd = IVD_CMD_VIDEO_CTL;
            s_ctl_decode_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
            s_ctl_decode_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);

            s_ctl_decode_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
            res = ivd_cxa_api_function((iv_obj_t *)hevcdec->s_app_ctx.cocodec_obj, (void *)&s_ctl_decode_ip, (void *)&s_ctl_decode_op);
            if (IV_SUCCESS != res) {
                av_log(c, AV_LOG_ERROR, "decode set decode mode failed.");
		FAIL(-5);
	    }
#endif
	    hevcdec->inited = 1;
	    if (hevcdec->ps_out_buf->pu1_bufs[0] == NULL) {
	        disp_outbuf = (uint8_t*)malloc(outlen);
	        hevcdec->ps_out_buf->pu1_bufs[0] = disp_outbuf;
                hevcdec->ps_out_buf->u4_min_out_buf_size[0] = hevcdec->ps_out_buf->u4_min_out_buf_size[1] = 
			hevcdec->ps_out_buf->u4_min_out_buf_size[2] = AlignTo(c->width, 64) * AlignTo(c->height, 64);
                hevcdec->ps_out_buf->pu1_bufs[1] = hevcdec->ps_out_buf->pu1_bufs[0] + AlignTo(c->width, 64) * AlignTo(c->height, 64);
		hevcdec->ps_out_buf->pu1_bufs[2] = hevcdec->ps_out_buf->pu1_bufs[1] + AlignTo(c->width, 64) * AlignTo(c->height, 64);
	        hevcdec->ps_out_buf->u4_num_bufs = 3;
	    }
	    ivd_video_decode_ip_t s_video_decode_frame_ip;
            ivd_video_decode_op_t s_video_decode_frame_op;
            s_video_decode_frame_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
            s_video_decode_frame_ip.u4_ts = cur_dts;
            s_video_decode_frame_ip.pv_stream_buffer = pkt.data;
            s_video_decode_frame_ip.u4_num_Bytes = pkt.size;
            s_video_decode_frame_ip.u4_size = sizeof(ivd_video_decode_ip_t);
            s_video_decode_frame_ip.s_out_buffer.u4_min_out_buf_size[0] =
                            hevcdec->ps_out_buf->u4_min_out_buf_size[0];
            s_video_decode_frame_ip.s_out_buffer.u4_min_out_buf_size[1] =
                            hevcdec->ps_out_buf->u4_min_out_buf_size[1];
            s_video_decode_frame_ip.s_out_buffer.u4_min_out_buf_size[2] =
                            hevcdec->ps_out_buf->u4_min_out_buf_size[2];

            s_video_decode_frame_ip.s_out_buffer.pu1_bufs[0] =
                            hevcdec->ps_out_buf->pu1_bufs[0];
            s_video_decode_frame_ip.s_out_buffer.pu1_bufs[1] =
                            hevcdec->ps_out_buf->pu1_bufs[1];
            s_video_decode_frame_ip.s_out_buffer.pu1_bufs[2] =
                            hevcdec->ps_out_buf->pu1_bufs[2];
            s_video_decode_frame_ip.s_out_buffer.u4_num_bufs =
                            hevcdec->ps_out_buf->u4_num_bufs;

	    s_video_decode_frame_op.s_disp_frm_buf.pv_y_buf = hevcdec->ps_out_buf->pu1_bufs[0];
	    s_video_decode_frame_op.s_disp_frm_buf.pv_u_buf = hevcdec->ps_out_buf->pu1_bufs[1];
	    s_video_decode_frame_op.s_disp_frm_buf.pv_v_buf = hevcdec->ps_out_buf->pu1_bufs[2];

            s_video_decode_frame_op.u4_size = sizeof(ivd_video_decode_op_t);
            res = ivd_cxa_api_function((iv_obj_t *)hevcdec->s_app_ctx.cocodec_obj, (void *)&s_video_decode_frame_ip,
                                       (void *)&s_video_decode_frame_op);
	    if (res != IV_SUCCESS) {
	        av_log(c, AV_LOG_ERROR, "decode key frame failed. error %d.", s_video_decode_op.u4_error_code);
		FAIL(-4);
	    }
	    if (s_video_decode_frame_op.e_output_format != IV_YUV_420P 
		&& s_video_decode_frame_op.e_output_format != IV_YUV_420SP_UV
		&& s_video_decode_frame_op.e_output_format != IV_YUV_420SP_VU) {
	        av_log(c, AV_LOG_ERROR, "decode format not support. format %d.", s_video_decode_frame_op.e_output_format);
		FAIL(-5);
	    }

	    if (frame && s_video_decode_op.u4_frame_decoded_flag) {
	        if (libhevcdec_fill_frame_withbuf(c, frame, &s_video_decode_frame_op, &s_video_decode_frame_ip) != 0) {
		    av_log(c, AV_LOG_ERROR, "fill frame failed.");
		    FAIL(-6);
		}
	    }
	    c->pix_fmt = AV_PIX_FMT_YUV420P;
	    SUCCESS();
	}

	if (libhevcdec_hvcc2annexb(c, &pkt) != 0) {
	    av_log(c, AV_LOG_ERROR, "libhevcdec_hvcc2annexb failed.");
	    FAIL(-15);
	}
        ivd_video_decode_ip_t s_video_decode_ip;
        ivd_video_decode_op_t s_video_decode_op; 
        s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
        s_video_decode_ip.u4_ts = cur_dts;
    	s_video_decode_ip.pv_stream_buffer = pkt.data;
        s_video_decode_ip.u4_num_Bytes = pkt.size;
        s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t);
        s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[0] =
                            hevcdec->ps_out_buf->u4_min_out_buf_size[0];
        s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] =
                            hevcdec->ps_out_buf->u4_min_out_buf_size[1];
        s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[2] =
                            hevcdec->ps_out_buf->u4_min_out_buf_size[2];

        s_video_decode_ip.s_out_buffer.pu1_bufs[0] =
                            hevcdec->ps_out_buf->pu1_bufs[0];
        s_video_decode_ip.s_out_buffer.pu1_bufs[1] =
                            hevcdec->ps_out_buf->pu1_bufs[1];
        s_video_decode_ip.s_out_buffer.pu1_bufs[2] =
                            hevcdec->ps_out_buf->pu1_bufs[2];
        s_video_decode_ip.s_out_buffer.u4_num_bufs =
                            hevcdec->ps_out_buf->u4_num_bufs;
        s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t);
	res = ivd_cxa_api_function((iv_obj_t *)hevcdec->s_app_ctx.cocodec_obj, (void *)&s_video_decode_ip,
                                       (void *)&s_video_decode_op);
	if (res != IV_SUCCESS) {
            av_log(c, AV_LOG_ERROR, "Error in video Frame decode : res %x Error %x\n", res,
                       s_video_decode_op.u4_error_code);
	    FAIL(-8);
        }
	if (frame && s_video_decode_op.u4_frame_decoded_flag && s_video_decode_op.u4_output_present) {
	    if (libhevcdec_fill_frame_withbuf(c, frame, &s_video_decode_op, &s_video_decode_ip) != 0) {
                av_log(c, AV_LOG_ERROR, "fill frame failed.");
	        FAIL(-9);
            }
	}
        if (s_video_decode_op.u4_output_present) {
    //        fprintf(stderr, "linesize[%d %d %d] resolution[%dx%d]type[%d]\n", frame->linesize[0], frame->linesize[1], frame->linesize[2], frame->width, frame->height, frame->pict_type);
        }
    }
    SUCCESS();
}

static av_cold int libhevcdec_close(AVCodecContext *c)
{
    LibhevcdecContext *libhevc = (LibhevcdecContext*)c->priv_data;
    if (libhevc->ps_out_buf->pu1_bufs[0]) {
        free(libhevc->ps_out_buf->pu1_bufs[0]);
        libhevc->ps_out_buf->pu1_bufs[0] = libhevc->ps_out_buf->pu1_bufs[1] = libhevc->ps_out_buf->pu1_bufs[2] = NULL;
    }

    if (libhevc->ps_out_buf) {
        free(libhevc->ps_out_buf);
        libhevc->ps_out_buf = NULL;
    }

    if (libhevc->bsf_context) {
        av_bsf_free(&libhevc->bsf_context);
        libhevc->bsf_context = NULL;
    }
    return 0;
}
#define OFFSET(x) offsetof(LibhevcdecContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption hevcdec_options[] = {
    { "numcores", "decode cores", OFFSET(num_cores), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 16, VD},
    { "cpusimd",        "Set the cpu simd",   OFFSET(cpu_simd),        AV_OPT_TYPE_STRING, { .str = "ARM_NEONINTR" }, 0, 0, VD},
    { NULL }
};

static const AVClass libhevcdec_class = {
    .class_name = "libhevcdec",
    .item_name  = av_default_item_name,
    .option     = hevcdec_options,
    .version    = LIBAVUTIL_VERSION_INT,
};

const FFCodec ff_libhevcdec_decoder = {
    .p.name         = "libhevcdec",
    .p.long_name    = NULL_IF_CONFIG_SMALL("libhevcdec hevc  decoder by VideoLAN"),
    .p.type         = AVMEDIA_TYPE_VIDEO,
    .p.id           = AV_CODEC_ID_HEVC,
    .priv_data_size = sizeof(LibhevcdecContext),
    .init           = libhevcdec_init,
    .close          = libhevcdec_close,
    .flush          = libhevcdec_flush,
    FF_CODEC_RECEIVE_FRAME_CB(libhevcdec_receive_frame),
    .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS,
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_SETS_PKT_DTS |
                      FF_CODEC_CAP_AUTO_THREADS,
    .p.priv_class   = &libhevcdec_class,
    .p.wrapper_name = "libhevcdec",
};

参考别的库引入,在configure脚本里面加上配置项,然后configure一下,就能编译了。

 --enable-libhevcdec --enable-libx264 --enable-gpl --extra-cflags='-I/data/decoder/libhevc/decoder -I/data/decoder/libhevc/common' --extra-ldflags='-L /data/decoder/libhevc/build/' --extra-libs='-lhevcdec -ldl -lm' --disable-ffplay

解码命令示例:

./ffmpeg_g -vcodec libhevcdec -vsync 0 -i chiji.mp4 -y 123.yuv

配置不会可以发邮件,1045056991@qq.com

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐