int vpx_video_writer_write_frame(VpxVideoWriter *writer,
                                 const uint8_t *buffer, size_t size,
                                 int64_t pts) {
  ivf_write_frame_header(writer->file, pts, size);
  if (fwrite(buffer, 1, size, writer->file) != size)
    return 0;

  ++writer->frame_count;

  return 1;
}
int main(int argc, const char **argv) {
    AppInput app_input = {0};
    FILE *outfile;
    vpx_codec_ctx_t codec;
    vpx_codec_enc_cfg_t enc_cfg;
    SvcContext svc_ctx;
    uint32_t i;
    uint32_t frame_cnt = 0;
    vpx_image_t raw;
    vpx_codec_err_t res;
    int pts = 0;            /* PTS starts at 0 */
    int frame_duration = 1; /* 1 timebase tick per frame */
    vpx_codec_cx_pkt_t packet = {0};
    packet.kind = VPX_CODEC_CX_FRAME_PKT;

    memset(&svc_ctx, 0, sizeof(svc_ctx));
    svc_ctx.log_print = 1;
    exec_name = argv[0];
    parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg);

    // Allocate image buffer
    if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32))
        die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h);

    if (!(app_input.input_ctx.file = fopen(app_input.input_ctx.filename, "rb")))
        die("Failed to open %s for reading\n", app_input.input_ctx.filename);

    if (!(outfile = fopen(app_input.output_filename, "wb")))
        die("Failed to open %s for writing\n", app_input.output_filename);

    // Initialize codec
    if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) !=
            VPX_CODEC_OK)
        die("Failed to initialize encoder\n");

    ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, 0);

    // skip initial frames
    for (i = 0; i < app_input.frames_to_skip; ++i) {
        read_yuv_frame(&app_input.input_ctx, &raw);
    }

    // Encode frames
    while (frame_cnt < app_input.frames_to_code) {
        if (read_yuv_frame(&app_input.input_ctx, &raw)) break;

        res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration,
                             VPX_DL_REALTIME);
        printf("%s", vpx_svc_get_message(&svc_ctx));
        if (res != VPX_CODEC_OK) {
            die_codec(&codec, "Failed to encode frame");
        }
        if (vpx_svc_get_frame_size(&svc_ctx) > 0) {
            packet.data.frame.pts = pts;
            packet.data.frame.sz = vpx_svc_get_frame_size(&svc_ctx);
            ivf_write_frame_header(outfile, &packet);
            (void)fwrite(vpx_svc_get_buffer(&svc_ctx), 1,
                         vpx_svc_get_frame_size(&svc_ctx), outfile);
        }
        ++frame_cnt;
        pts += frame_duration;
    }

    printf("Processed %d frames\n", frame_cnt);

    fclose(app_input.input_ctx.file);
    if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");

    // rewrite the output file headers with the actual frame count, and
    // resolution of the highest layer
    if (!fseek(outfile, 0, SEEK_SET)) {
        // get resolution of highest layer
        if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(&svc_ctx,
                svc_ctx.spatial_layers - 1,
                &enc_cfg.g_w,
                &enc_cfg.g_h)) {
            die("Failed to get output resolution");
        }
        ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, frame_cnt);
    }
    fclose(outfile);
    vpx_img_free(&raw);

    // display average size, psnr
    printf("%s", vpx_svc_dump_statistics(&svc_ctx));

    vpx_svc_release(&svc_ctx);

    return EXIT_SUCCESS;
}