一 都说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