在ffmpeg上实现libhevc wrapper
一 都说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
更多推荐
所有评论(0)