美文网首页视频编码多媒体科技
AV1 libaom编码示例simple_encoder

AV1 libaom编码示例simple_encoder

作者: smallest_one | 来源:发表于2019-04-16 11:08 被阅读3次

    目录

    1. 参考
    2. 示例说明
    3. 示例代码

    1. 参考

    2. 示例说明

    示例主要参考了[1]。功能为把YUV420P的视频数据编码为AV1的压缩数据,使用IVF视频文件封装格式。


    libaom_simple_encoder.png

    说明:

    • aom_img_alloc():为结构体aom_image_t分配内存,用于存储未编码压缩的图像数据。
    • aom_codec_enc_config_default():设置参数集结构体aom_codec_enc_cfg_t的默认值。
    • aom_codec_enc_init:打开编码器,编码完成之后需使用aom_codec_destroy()关闭编码器。
    • ivf_write_header:写IVF封装格式的文件头。
    • aom_codec_encode():编码一帧图像。
    • aom_codec_get_cx_data():获取一帧压缩编码数据,数据存储在返回的aom_codec_cx_pkt_t结构体中。
    • ivf_write_frame():写IVF封装格式的文每帧数据。

    3. 示例代码

    #include <stdarg.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <aom/aom_encoder.h>
    #include <aom/aomcx.h>
    
    #define LOG_ERROR(label)               \
      do {                                 \
        const char *l = label;             \
        va_list ap;                        \
        va_start(ap, fmt);                 \
        if (l) fprintf(stderr, "%s: ", l); \
        vfprintf(stderr, fmt, ap);         \
        fprintf(stderr, "\n");             \
        va_end(ap);                        \
      } while (0)
    
    
    void io_w8(FILE *f, unsigned char b) {
        fwrite(&b, 1, 1, f);
    }
    
    void io_wl16(FILE *f, unsigned int val) {
        io_w8(f, (unsigned char)val);
        io_w8(f, (unsigned char)(val >> 8));
    }
    
    void io_wl32(FILE *f, unsigned int val) {
        io_wl16(f,  val & 0xffff);
        io_wl16(f, (val >> 16));
    }
    
    void io_wl64(FILE *f, uint64_t val) {
        io_wl32(f, (uint32_t)(val & 0xffffffff));
        io_wl32(f, (uint32_t)(val >> 32));
    }
    
    static int ivf_write_header(FILE *f, int width, int height, int framerate, int timescale) {
        fwrite("DKIF", 1, 4, f);
        io_wl16(f, 0);//version;
        io_wl16(f, 32); //header length
        fwrite("AV01", 1, 4, f);
        io_wl16(f, width);
        io_wl16(f, height);
        io_wl32(f, framerate);
        io_wl32(f, timescale);
        io_wl32(f, 0);//frame_count
        io_wl32(f, 0);//unused
        return 0;
    }
    
    static int ivf_write_frame(FILE *f, void *buf, int size, int64_t pts) {
        io_wl32(f, size);
        io_wl64(f, pts);
        fwrite(buf, 1, size, f);
        return 0;
    }
    
    static int write_header(FILE *f, int width, int height, int framerate, int timescale) {
        return ivf_write_header(f, width, height, framerate, timescale);
    }
    
    static int write_frame(FILE *outfile, void *buf, size_t sz, aom_codec_pts_t pts) {
        return ivf_write_frame(outfile, buf, sz, pts);
    }
    
    static int img_read(aom_image_t *img, FILE *file) {
      int plane;
    
      for (plane = 0; plane < 3; ++plane) {
        unsigned char *buf = img->planes[plane];
        const int stride = img->stride[plane];
        const int w = aom_img_plane_width(img, plane) *
                      ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
        const int h = aom_img_plane_height(img, plane);
        int y;
    
        for (y = 0; y < h; ++y) {
          if (fread(buf, 1, w, file) != (size_t)w) return 0;
          buf += stride;
        }
      }
    
      return 1;
    }
    
    static const char *exec_name;
    void usage_exit(void) {
      fprintf(stderr,
              "Usage: %s <width> <height> <infile> <outfile> <fps> <keyframe-interval> \n",
              exec_name);
      exit(EXIT_FAILURE);
    }
    
    
    void die(const char *fmt, ...) {
      LOG_ERROR(NULL);
      usage_exit();
    }
    
    void die_codec(aom_codec_ctx_t *ctx, const char *s) {
      const char *detail = aom_codec_error_detail(ctx);
    
      fprintf(stderr, "%s: %s\n", s, aom_codec_error(ctx));
      if (detail) printf("    %s\n", detail);
      exit(EXIT_FAILURE);
    }
    
    static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img,
                            int frame_index, int flags, FILE*outfile) {
      int got_pkts = 0;
      aom_codec_iter_t iter = NULL;
      const aom_codec_cx_pkt_t *pkt = NULL;
    
      const aom_codec_err_t res =
          aom_codec_encode(codec, img, frame_index, 1, flags);
      if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame");
    
      while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) {
        got_pkts = 1;
        if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
          const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0;
          if (write_frame(outfile, pkt->data.frame.buf,
                                            pkt->data.frame.sz,
                                            pkt->data.frame.pts) < 0) {
            die_codec(codec, "Failed to write compressed frame");
          }
          printf(keyframe ? "K" : ".");
          fflush(stdout);
        }
      }
      return got_pkts;
    }
    
    int main(int argc, char **argv) {
      FILE *infile = NULL;
      FILE *outfile = NULL;
      aom_codec_ctx_t codec;
      aom_codec_enc_cfg_t cfg;
      aom_image_t img;
      aom_codec_err_t res;
      int frame_count = 0;
    
      const int bitrate = 1500;
      int fps = 0;
      int keyframe_interval = 0;
      int frames_encoded = 0;
      int width = 0;
      int height = 0;
      const char *infile_arg = NULL;
      const char *outfile_arg = NULL;
      const char *keyframe_interval_arg = NULL;
      exec_name = argv[0];
      if (argc != 7) die("Invalid number of arguments");
    
      width = (int)strtol(argv[1], NULL, 0);
      height = (int)strtol(argv[2], NULL, 0);
    
      if (width <= 0 || height <= 0 ||
          (width % 2) != 0 || (height % 2) != 0) {
        die("Invalid frame size: %dx%d", width, height);
      }
    
      infile_arg = argv[3];
      outfile_arg = argv[4];
    
      fps = (int)strtol(argv[5], NULL, 0);
      if (fps <= 0) die("Invalid fps value.");
    
      keyframe_interval = (int)strtol(argv[6], NULL, 0);
      if (keyframe_interval < 0) die("Invalid keyframe interval value.");
    
      fprintf(stdout, "aom_codec_version:%s\n", aom_codec_version_str());
      fprintf(stdout, "aom_codec_build_config:%s\n", aom_codec_build_config());
    
      const struct aom_codec_iface *iface = aom_codec_av1_cx();
    
      if (!aom_img_alloc(&img, AOM_IMG_FMT_I420, width,
                         height, 1)) {
        die("Failed to allocate image.");
      }
    
      res = aom_codec_enc_config_default(iface, &cfg, 0);
      if (res) die_codec(&codec, "Failed to get default codec config.");
    
      cfg.g_w = width;
      cfg.g_h = height;
      cfg.g_timebase.num = 1;
      cfg.g_timebase.den = fps;
      cfg.rc_target_bitrate = bitrate;
    
      if (!(infile = fopen(infile_arg, "rb")))
        fprintf(stderr,"Failed to open %s for reading.", infile_arg);
    
      if (!(outfile = fopen(outfile_arg, "wb"))) {
        fprintf(stderr, "Failed to open %s for writing.", outfile_arg);
      }
    
      if (aom_codec_enc_init(&codec, iface, &cfg, 0))
        die_codec(&codec, "Failed to initialize encoder");
    
      write_header(outfile, width, height, fps, 1);  
    
      // Encode frames.
      while (img_read(&img, infile)) {
        int flags = 0;
        if (keyframe_interval > 0 && frame_count % keyframe_interval == 0)
          flags |= AOM_EFLAG_FORCE_KF;
        encode_frame(&codec, &img, frame_count++, flags, outfile);
        frames_encoded++;
      }
    
      // Flush encoder.
      while (encode_frame(&codec, NULL, -1, 0, outfile)) continue;
      printf("\n");
      fclose(infile);
      fclose(outfile);
      printf("Processed %d frames.\n", frame_count);
      aom_img_free(&img);
      if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
    
      return EXIT_SUCCESS;
    }
    
    • 示例的使用方法Usage: simple_encoder <width> <height> <infile> <outfile> <fps> <keyframe-interval>,例如下面的运行命令。
    simple_encode 1280 720 julin.yuv julin.ivf 25 0
    

    相关文章

      网友评论

        本文标题:AV1 libaom编码示例simple_encoder

        本文链接:https://www.haomeiwen.com/subject/skuvwqtx.html