有时候需要各种编码,不同系统编码方式又不一样,怎么提供一个好的接口支持多个平台。于是参考了ffmpeg。
API接口定义
1. 核心数组codec_list
在ffmpeg有一个codec_list数组,他把所有支持的编码器都写在数组里面。然后通过调用avcodec_find_encoder_by_name或者avcodec_find_encoder去查找想要的编码器。于是我改一下:
#ifndef _hi_codecs_h_
#define _hi_codecs_h_
#include <stdint.h>
#include <string.h>
#include "avframe.h"
#include "avpacket.h"
#include "avcodecid.h"
#ifdef __cplusplus
extern "C" {
#endif
#define HI_CODEC_FLAG_GLOBAL_HEADER (1 << 22)
struct audio_parameter_t
{
int format; // enum pcm_sample_format
int channels; // 1, 2
int samplerate; // 8000, 16000, 24000, 32000, 44100, 48000
int profile;
int level;
int bitrate;
int bitrate_mode; // CBR/VBR
int min_bitrate_kbps; // vbr only
int max_bitrate_kbps; // vbr only
};
struct video_parameter_t
{
int global_quality;
int flags;
int codecid;
int profile; // H264_PROFILE_XXX
int level; // H264_LEVEL_XXX
int num; ///< Numerator
int den; ///< Denominator
int width;
int height;
int format; // PICTURE_YUV420/PICTURE_YUV422/PICTURE_YUV444
int64_t rc_max_rate;
int frame_rate; // 25000/1000.0 => 25.0fps
int gop_size; // frames per gop
int bitrate; // bits per second
int bitrate_mode; // 1CBR/2VBR/3ABR/4CQP/5CRF
int forced_idr;
int stream_mode; // 0-H.264 AnnexB, 1-H.264 MP4
};
typedef union hi_parameter_t {
struct audio_parameter_t a;
struct video_parameter_t v;
} hi_parameter_t;
typedef struct HICodec
{
const char* name;
enum AVPACKET_CODEC_ID id;
//int (*init)(void* h264);
void* (*create)(const hi_parameter_t* param);
void (*destroy)(void* h264);
/// pic->flags & AVPACKET_FLAG_KEY => force IDR
/// @return >0-ok, other-error
int (*input)(void* h264, const struct avframe_t* pic);
/// @return >=0-got packet, <0-error
int (*getpacket)(void* h264, struct avpacket_t* pkt);
void (*init_static_data)(struct HICodec* codec); // Function pointer for static data initialization
}HICodec;
int hi_codec_init_static(void);
const HICodec* hicodec_find_encoder(enum AVPACKET_CODEC_ID id);
const HICodec* hicodec_find_encoder_by_name(const char* name);
#ifdef __cplusplus
}
#endif
#endif /* !_hi_codecs_h_ *
注:hi_codec_init_static 这个接口是用来加载一些编码库,比如qsv要提前初始化它的库,因为MFXInitEx这个接口加载很慢,我们提前加载。如果不需要提前加载只需要把.init_static_data 置为NULL。
#include "hicodecs.h"
#include <stdint.h>
#include <string.h>
#include "avstring.h"
extern const HICodec qsv_encoder;
extern const HICodec cuda_encoder;
extern const HICodec libx264_encoder;
extern const HICodec libx265_encoder;
const HICodec* codec_list[] = {
&cuda_encoder,
&qsv_encoder,
&libx264_encoder,
&libx265_encoder,
// Add more codec pointers as needed
NULL
};
int hi_codec_init_static(void)
{
for (int i = 0; codec_list[i]; i++) {
if (codec_list[i]->init_static_data)
codec_list[i]->init_static_data((HICodec*)codec_list[i]);
}
return 0;
}
const HICodec* hi_codec_iterate(void** opaque)
{
uintptr_t i = (uintptr_t)*opaque;
const HICodec* c = codec_list[i];
if (c) {
(*opaque) = (void*)(i + 1);
return c;
}
return NULL;
}
//static const HICodec* find_codec(enum AVPACKET_CODEC_ID id, int (*x)(const HICodec*))
static const HICodec* find_codec(enum AVPACKET_CODEC_ID id)
{
const HICodec* p=NULL;
void* i = 0;
while ((p = hi_codec_iterate(&i))) {
/* if (!x(p))
continue;*/
if (p->id == id) {
return p;
}
}
return NULL;
}
static const HICodec* find_codec_by_name(const char* name)
{
const HICodec* p = NULL;
void* i = 0;
while ((p = hi_codec_iterate(&i))) {
/* if (!x(p))
continue;*/
if (av_strcasecmp(name, p->name) == 0)
return p;
}
return NULL;
}
const HICodec* hicodec_find_encoder_by_name(const char* name)
{
return find_codec_by_name(name);
}
按照上面的接口我们想对接cuda,那只需要实现cuda的编码:
static void* nvenc_create(hi_parameter_t* avctx)
{
return p;
}
static void nvenc_destroy(void* nven)
{
}
static int nvenc_send_frame(NvencContext* ctx, const struct avframe_t* frame)
{
return
}
int nvenc_receive_packet(NvencContext* ctx, struct avpacket_t* pkt)
{
return 0;
}
const HICodec cuda_encoder = {
.name = "cuda",
// .id = AV_CODEC_ID_H264,
// .init = qsv_enc_init,
.create = nvenc_create,
.destroy = nvenc_destroy,
.input = nvenc_send_frame,
.getpacket = nvenc_receive_packet,
.init_static_data = NULL, // Assign the initialization function
};
2. 调用demo
p->en =(HICodec*) hicodec_find_encoder_by_name("cuda");
hi_parameter_t co;
memset(&co, 0, sizeof( hi_parameter_t));
co.v.codecid = AVCODEC_VIDEO_H265;
co.v.format = PICTURE_NV12;
co.v.height = h;
co.v.width = w;
co.v.num = 25;
co.v.den = 1;
co.v.gop_size = 25;
co.v.bitrate = 50000000;
co.v.rc_max_rate = 50000000;
co.v.frame_rate = 25000;
co.v.flags |= HI_CODEC_FLAG_GLOBAL_HEADER;
co.v.forced_idr = 1;
co.v.bitrate_mode = 5;
p->id = p->en->create(&co);
作者:Aliveyun
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。