如何设置多种编码器的支持

有时候需要各种编码,不同系统编码方式又不一样,怎么提供一个好的接口支持多个平台。于是参考了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 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论