1233d2500723e5594f3e7c70896ffeeef32b9c950ywan/* 2233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3233d2500723e5594f3e7c70896ffeeef32b9c950ywan * 4233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Use of this source code is governed by a BSD-style license 5233d2500723e5594f3e7c70896ffeeef32b9c950ywan * that can be found in the LICENSE file in the root of the source 6233d2500723e5594f3e7c70896ffeeef32b9c950ywan * tree. An additional intellectual property rights grant can be found 7233d2500723e5594f3e7c70896ffeeef32b9c950ywan * in the file PATENTS. All contributing project authors may 8233d2500723e5594f3e7c70896ffeeef32b9c950ywan * be found in the AUTHORS file in the root of the source tree. 9233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 10233d2500723e5594f3e7c70896ffeeef32b9c950ywan 11233d2500723e5594f3e7c70896ffeeef32b9c950ywan/* 12233d2500723e5594f3e7c70896ffeeef32b9c950ywan * This is an example demonstrating multi-resolution encoding in VP8. 13233d2500723e5594f3e7c70896ffeeef32b9c950ywan * High-resolution input video is down-sampled to lower-resolutions. The 14233d2500723e5594f3e7c70896ffeeef32b9c950ywan * encoder then encodes the video and outputs multiple bitstreams with 15233d2500723e5594f3e7c70896ffeeef32b9c950ywan * different resolutions. 16233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 17233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdio.h> 18233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdlib.h> 19233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdarg.h> 20233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <string.h> 21233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <math.h> 22233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define VPX_CODEC_DISABLE_COMPAT 1 23233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx/vpx_encoder.h" 24233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx/vp8cx.h" 25233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx_ports/mem_ops.h" 26233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "./tools_common.h" 27233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define interface (vpx_codec_vp8_cx()) 28233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define fourcc 0x30385056 29233d2500723e5594f3e7c70896ffeeef32b9c950ywan 30233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define IVF_FILE_HDR_SZ (32) 31233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define IVF_FRAME_HDR_SZ (12) 32233d2500723e5594f3e7c70896ffeeef32b9c950ywan 33233d2500723e5594f3e7c70896ffeeef32b9c950ywan/* 34233d2500723e5594f3e7c70896ffeeef32b9c950ywan * The input video frame is downsampled several times to generate a multi-level 35233d2500723e5594f3e7c70896ffeeef32b9c950ywan * hierarchical structure. NUM_ENCODERS is defined as the number of encoding 36233d2500723e5594f3e7c70896ffeeef32b9c950ywan * levels required. For example, if the size of input video is 1280x720, 37233d2500723e5594f3e7c70896ffeeef32b9c950ywan * NUM_ENCODERS is 3, and down-sampling factor is 2, the encoder outputs 3 38233d2500723e5594f3e7c70896ffeeef32b9c950ywan * bitstreams with resolution of 1280x720(level 0), 640x360(level 1), and 39233d2500723e5594f3e7c70896ffeeef32b9c950ywan * 320x180(level 2) respectively. 40233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 41233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define NUM_ENCODERS 3 42233d2500723e5594f3e7c70896ffeeef32b9c950ywan 43233d2500723e5594f3e7c70896ffeeef32b9c950ywan/* This example uses the scaler function in libyuv. */ 44233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "third_party/libyuv/include/libyuv/basic_types.h" 45233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "third_party/libyuv/include/libyuv/scale.h" 46233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "third_party/libyuv/include/libyuv/cpu_id.h" 47233d2500723e5594f3e7c70896ffeeef32b9c950ywan 48233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void die(const char *fmt, ...) { 49233d2500723e5594f3e7c70896ffeeef32b9c950ywan va_list ap; 50233d2500723e5594f3e7c70896ffeeef32b9c950ywan 51233d2500723e5594f3e7c70896ffeeef32b9c950ywan va_start(ap, fmt); 52233d2500723e5594f3e7c70896ffeeef32b9c950ywan vprintf(fmt, ap); 53233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(fmt[strlen(fmt)-1] != '\n') 54233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("\n"); 55233d2500723e5594f3e7c70896ffeeef32b9c950ywan exit(EXIT_FAILURE); 56233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 57233d2500723e5594f3e7c70896ffeeef32b9c950ywan 58233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void die_codec(vpx_codec_ctx_t *ctx, const char *s) { 59233d2500723e5594f3e7c70896ffeeef32b9c950ywan const char *detail = vpx_codec_error_detail(ctx); 60233d2500723e5594f3e7c70896ffeeef32b9c950ywan 61233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("%s: %s\n", s, vpx_codec_error(ctx)); 62233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(detail) 63233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf(" %s\n",detail); 64233d2500723e5594f3e7c70896ffeeef32b9c950ywan exit(EXIT_FAILURE); 65233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 66233d2500723e5594f3e7c70896ffeeef32b9c950ywan 67233d2500723e5594f3e7c70896ffeeef32b9c950ywanint (*read_frame_p)(FILE *f, vpx_image_t *img); 68233d2500723e5594f3e7c70896ffeeef32b9c950ywan 69233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int read_frame(FILE *f, vpx_image_t *img) { 70233d2500723e5594f3e7c70896ffeeef32b9c950ywan size_t nbytes, to_read; 71233d2500723e5594f3e7c70896ffeeef32b9c950ywan int res = 1; 72233d2500723e5594f3e7c70896ffeeef32b9c950ywan 73233d2500723e5594f3e7c70896ffeeef32b9c950ywan to_read = img->w*img->h*3/2; 74233d2500723e5594f3e7c70896ffeeef32b9c950ywan nbytes = fread(img->planes[0], 1, to_read, f); 75233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(nbytes != to_read) { 76233d2500723e5594f3e7c70896ffeeef32b9c950ywan res = 0; 77233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(nbytes > 0) 78233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("Warning: Read partial frame. Check your width & height!\n"); 79233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 80233d2500723e5594f3e7c70896ffeeef32b9c950ywan return res; 81233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 82233d2500723e5594f3e7c70896ffeeef32b9c950ywan 83233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int read_frame_by_row(FILE *f, vpx_image_t *img) { 84233d2500723e5594f3e7c70896ffeeef32b9c950ywan size_t nbytes, to_read; 85233d2500723e5594f3e7c70896ffeeef32b9c950ywan int res = 1; 86233d2500723e5594f3e7c70896ffeeef32b9c950ywan int plane; 87233d2500723e5594f3e7c70896ffeeef32b9c950ywan 88233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (plane = 0; plane < 3; plane++) 89233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 90233d2500723e5594f3e7c70896ffeeef32b9c950ywan unsigned char *ptr; 91233d2500723e5594f3e7c70896ffeeef32b9c950ywan int w = (plane ? (1 + img->d_w) / 2 : img->d_w); 92233d2500723e5594f3e7c70896ffeeef32b9c950ywan int h = (plane ? (1 + img->d_h) / 2 : img->d_h); 93233d2500723e5594f3e7c70896ffeeef32b9c950ywan int r; 94233d2500723e5594f3e7c70896ffeeef32b9c950ywan 95233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Determine the correct plane based on the image format. The for-loop 96233d2500723e5594f3e7c70896ffeeef32b9c950ywan * always counts in Y,U,V order, but this may not match the order of 97233d2500723e5594f3e7c70896ffeeef32b9c950ywan * the data on disk. 98233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 99233d2500723e5594f3e7c70896ffeeef32b9c950ywan switch (plane) 100233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 101233d2500723e5594f3e7c70896ffeeef32b9c950ywan case 1: 102233d2500723e5594f3e7c70896ffeeef32b9c950ywan ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U]; 103233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 104233d2500723e5594f3e7c70896ffeeef32b9c950ywan case 2: 105233d2500723e5594f3e7c70896ffeeef32b9c950ywan ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V]; 106233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 107233d2500723e5594f3e7c70896ffeeef32b9c950ywan default: 108233d2500723e5594f3e7c70896ffeeef32b9c950ywan ptr = img->planes[plane]; 109233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 110233d2500723e5594f3e7c70896ffeeef32b9c950ywan 111233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (r = 0; r < h; r++) 112233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 113233d2500723e5594f3e7c70896ffeeef32b9c950ywan to_read = w; 114233d2500723e5594f3e7c70896ffeeef32b9c950ywan 115233d2500723e5594f3e7c70896ffeeef32b9c950ywan nbytes = fread(ptr, 1, to_read, f); 116233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(nbytes != to_read) { 117233d2500723e5594f3e7c70896ffeeef32b9c950ywan res = 0; 118233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(nbytes > 0) 119233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("Warning: Read partial frame. Check your width & height!\n"); 120233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 121233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 122233d2500723e5594f3e7c70896ffeeef32b9c950ywan 123233d2500723e5594f3e7c70896ffeeef32b9c950ywan ptr += img->stride[plane]; 124233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 125233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (!res) 126233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 127233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 128233d2500723e5594f3e7c70896ffeeef32b9c950ywan 129233d2500723e5594f3e7c70896ffeeef32b9c950ywan return res; 130233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 131233d2500723e5594f3e7c70896ffeeef32b9c950ywan 132233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void write_ivf_file_header(FILE *outfile, 133233d2500723e5594f3e7c70896ffeeef32b9c950ywan const vpx_codec_enc_cfg_t *cfg, 134233d2500723e5594f3e7c70896ffeeef32b9c950ywan int frame_cnt) { 135233d2500723e5594f3e7c70896ffeeef32b9c950ywan char header[32]; 136233d2500723e5594f3e7c70896ffeeef32b9c950ywan 137233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS) 138233d2500723e5594f3e7c70896ffeeef32b9c950ywan return; 139233d2500723e5594f3e7c70896ffeeef32b9c950ywan header[0] = 'D'; 140233d2500723e5594f3e7c70896ffeeef32b9c950ywan header[1] = 'K'; 141233d2500723e5594f3e7c70896ffeeef32b9c950ywan header[2] = 'I'; 142233d2500723e5594f3e7c70896ffeeef32b9c950ywan header[3] = 'F'; 143233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le16(header+4, 0); /* version */ 144233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le16(header+6, 32); /* headersize */ 145233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+8, fourcc); /* headersize */ 146233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le16(header+12, cfg->g_w); /* width */ 147233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le16(header+14, cfg->g_h); /* height */ 148233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+16, cfg->g_timebase.den); /* rate */ 149233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+20, cfg->g_timebase.num); /* scale */ 150233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+24, frame_cnt); /* length */ 151233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+28, 0); /* unused */ 152233d2500723e5594f3e7c70896ffeeef32b9c950ywan 153233d2500723e5594f3e7c70896ffeeef32b9c950ywan (void) fwrite(header, 1, 32, outfile); 154233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 155233d2500723e5594f3e7c70896ffeeef32b9c950ywan 156233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void write_ivf_frame_header(FILE *outfile, 157233d2500723e5594f3e7c70896ffeeef32b9c950ywan const vpx_codec_cx_pkt_t *pkt) 158233d2500723e5594f3e7c70896ffeeef32b9c950ywan{ 159233d2500723e5594f3e7c70896ffeeef32b9c950ywan char header[12]; 160233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_codec_pts_t pts; 161233d2500723e5594f3e7c70896ffeeef32b9c950ywan 162233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(pkt->kind != VPX_CODEC_CX_FRAME_PKT) 163233d2500723e5594f3e7c70896ffeeef32b9c950ywan return; 164233d2500723e5594f3e7c70896ffeeef32b9c950ywan 165233d2500723e5594f3e7c70896ffeeef32b9c950ywan pts = pkt->data.frame.pts; 166233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header, pkt->data.frame.sz); 167233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+4, pts&0xFFFFFFFF); 168233d2500723e5594f3e7c70896ffeeef32b9c950ywan mem_put_le32(header+8, pts >> 32); 169233d2500723e5594f3e7c70896ffeeef32b9c950ywan 170233d2500723e5594f3e7c70896ffeeef32b9c950ywan (void) fwrite(header, 1, 12, outfile); 171233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 172233d2500723e5594f3e7c70896ffeeef32b9c950ywan 173233d2500723e5594f3e7c70896ffeeef32b9c950ywanint main(int argc, char **argv) 174233d2500723e5594f3e7c70896ffeeef32b9c950ywan{ 175233d2500723e5594f3e7c70896ffeeef32b9c950ywan FILE *infile, *outfile[NUM_ENCODERS]; 176233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_codec_ctx_t codec[NUM_ENCODERS]; 177233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_codec_enc_cfg_t cfg[NUM_ENCODERS]; 178233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_codec_pts_t frame_cnt = 0; 179233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_image_t raw[NUM_ENCODERS]; 180233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_codec_err_t res[NUM_ENCODERS]; 181233d2500723e5594f3e7c70896ffeeef32b9c950ywan 182233d2500723e5594f3e7c70896ffeeef32b9c950ywan int i; 183233d2500723e5594f3e7c70896ffeeef32b9c950ywan long width; 184233d2500723e5594f3e7c70896ffeeef32b9c950ywan long height; 185233d2500723e5594f3e7c70896ffeeef32b9c950ywan int frame_avail; 186233d2500723e5594f3e7c70896ffeeef32b9c950ywan int got_data; 187233d2500723e5594f3e7c70896ffeeef32b9c950ywan int flags = 0; 188233d2500723e5594f3e7c70896ffeeef32b9c950ywan 189233d2500723e5594f3e7c70896ffeeef32b9c950ywan /*Currently, only realtime mode is supported in multi-resolution encoding.*/ 190233d2500723e5594f3e7c70896ffeeef32b9c950ywan int arg_deadline = VPX_DL_REALTIME; 191233d2500723e5594f3e7c70896ffeeef32b9c950ywan 192233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Set show_psnr to 1/0 to show/not show PSNR. Choose show_psnr=0 if you 193233d2500723e5594f3e7c70896ffeeef32b9c950ywan don't need to know PSNR, which will skip PSNR calculation and save 194233d2500723e5594f3e7c70896ffeeef32b9c950ywan encoding time. */ 195233d2500723e5594f3e7c70896ffeeef32b9c950ywan int show_psnr = 0; 196233d2500723e5594f3e7c70896ffeeef32b9c950ywan uint64_t psnr_sse_total[NUM_ENCODERS] = {0}; 197233d2500723e5594f3e7c70896ffeeef32b9c950ywan uint64_t psnr_samples_total[NUM_ENCODERS] = {0}; 198233d2500723e5594f3e7c70896ffeeef32b9c950ywan double psnr_totals[NUM_ENCODERS][4] = {{0,0}}; 199233d2500723e5594f3e7c70896ffeeef32b9c950ywan int psnr_count[NUM_ENCODERS] = {0}; 200233d2500723e5594f3e7c70896ffeeef32b9c950ywan 201233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Set the required target bitrates for each resolution level. 202233d2500723e5594f3e7c70896ffeeef32b9c950ywan * If target bitrate for highest-resolution level is set to 0, 203233d2500723e5594f3e7c70896ffeeef32b9c950ywan * (i.e. target_bitrate[0]=0), we skip encoding at that level. 204233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 205233d2500723e5594f3e7c70896ffeeef32b9c950ywan unsigned int target_bitrate[NUM_ENCODERS]={1000, 500, 100}; 206233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Enter the frame rate of the input video */ 207233d2500723e5594f3e7c70896ffeeef32b9c950ywan int framerate = 30; 208233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Set down-sampling factor for each resolution level. 209233d2500723e5594f3e7c70896ffeeef32b9c950ywan dsf[0] controls down sampling from level 0 to level 1; 210233d2500723e5594f3e7c70896ffeeef32b9c950ywan dsf[1] controls down sampling from level 1 to level 2; 211233d2500723e5594f3e7c70896ffeeef32b9c950ywan dsf[2] is not used. */ 212233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_rational_t dsf[NUM_ENCODERS] = {{2, 1}, {2, 1}, {1, 1}}; 213233d2500723e5594f3e7c70896ffeeef32b9c950ywan 214233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(argc!= (5+NUM_ENCODERS)) 215233d2500723e5594f3e7c70896ffeeef32b9c950ywan die("Usage: %s <width> <height> <infile> <outfile(s)> <output psnr?>\n", 216233d2500723e5594f3e7c70896ffeeef32b9c950ywan argv[0]); 217233d2500723e5594f3e7c70896ffeeef32b9c950ywan 218233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("Using %s\n",vpx_codec_iface_name(interface)); 219233d2500723e5594f3e7c70896ffeeef32b9c950ywan 220233d2500723e5594f3e7c70896ffeeef32b9c950ywan width = strtol(argv[1], NULL, 0); 221233d2500723e5594f3e7c70896ffeeef32b9c950ywan height = strtol(argv[2], NULL, 0); 222233d2500723e5594f3e7c70896ffeeef32b9c950ywan 223233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(width < 16 || width%2 || height <16 || height%2) 224233d2500723e5594f3e7c70896ffeeef32b9c950ywan die("Invalid resolution: %ldx%ld", width, height); 225233d2500723e5594f3e7c70896ffeeef32b9c950ywan 226233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Open input video file for encoding */ 227233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(!(infile = fopen(argv[3], "rb"))) 228233d2500723e5594f3e7c70896ffeeef32b9c950ywan die("Failed to open %s for reading", argv[3]); 229233d2500723e5594f3e7c70896ffeeef32b9c950ywan 230233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Open output file for each encoder to output bitstreams */ 231233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=0; i< NUM_ENCODERS; i++) 232233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 233233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(!target_bitrate[i]) 234233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 235233d2500723e5594f3e7c70896ffeeef32b9c950ywan outfile[i] = NULL; 236233d2500723e5594f3e7c70896ffeeef32b9c950ywan continue; 237233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 238233d2500723e5594f3e7c70896ffeeef32b9c950ywan 239233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(!(outfile[i] = fopen(argv[i+4], "wb"))) 240233d2500723e5594f3e7c70896ffeeef32b9c950ywan die("Failed to open %s for writing", argv[i+4]); 241233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 242233d2500723e5594f3e7c70896ffeeef32b9c950ywan 243233d2500723e5594f3e7c70896ffeeef32b9c950ywan show_psnr = strtol(argv[NUM_ENCODERS + 4], NULL, 0); 244233d2500723e5594f3e7c70896ffeeef32b9c950ywan 245233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Populate default encoder configuration */ 246233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=0; i< NUM_ENCODERS; i++) 247233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 248233d2500723e5594f3e7c70896ffeeef32b9c950ywan res[i] = vpx_codec_enc_config_default(interface, &cfg[i], 0); 249233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(res[i]) { 250233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("Failed to get config: %s\n", vpx_codec_err_to_string(res[i])); 251233d2500723e5594f3e7c70896ffeeef32b9c950ywan return EXIT_FAILURE; 252233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 253233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 254233d2500723e5594f3e7c70896ffeeef32b9c950ywan 255233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* 256233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Update the default configuration according to needs of the application. 257233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 258233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Highest-resolution encoder settings */ 259233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_w = width; 260233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_h = height; 261233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_threads = 1; /* number of threads used */ 262233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_dropframe_thresh = 30; 263233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_end_usage = VPX_CBR; 264233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_resize_allowed = 0; 265233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_min_quantizer = 4; 266233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_max_quantizer = 56; 267233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_undershoot_pct = 98; 268233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_overshoot_pct = 100; 269233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_buf_initial_sz = 500; 270233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_buf_optimal_sz = 600; 271233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_buf_sz = 1000; 272233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_error_resilient = 1; /* Enable error resilient mode */ 273233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_lag_in_frames = 0; 274233d2500723e5594f3e7c70896ffeeef32b9c950ywan 275233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Disable automatic keyframe placement */ 276233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Note: These 3 settings are copied to all levels. But, except the lowest 277233d2500723e5594f3e7c70896ffeeef32b9c950ywan * resolution level, all other levels are set to VPX_KF_DISABLED internally. 278233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 279233d2500723e5594f3e7c70896ffeeef32b9c950ywan //cfg[0].kf_mode = VPX_KF_DISABLED; 280233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].kf_mode = VPX_KF_AUTO; 281233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].kf_min_dist = 3000; 282233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].kf_max_dist = 3000; 283233d2500723e5594f3e7c70896ffeeef32b9c950ywan 284233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].rc_target_bitrate = target_bitrate[0]; /* Set target bitrate */ 285233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_timebase.num = 1; /* Set fps */ 286233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[0].g_timebase.den = framerate; 287233d2500723e5594f3e7c70896ffeeef32b9c950ywan 288233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Other-resolution encoder settings */ 289233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=1; i< NUM_ENCODERS; i++) 290233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 291233d2500723e5594f3e7c70896ffeeef32b9c950ywan memcpy(&cfg[i], &cfg[0], sizeof(vpx_codec_enc_cfg_t)); 292233d2500723e5594f3e7c70896ffeeef32b9c950ywan 293233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[i].g_threads = 1; /* number of threads used */ 294233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[i].rc_target_bitrate = target_bitrate[i]; 295233d2500723e5594f3e7c70896ffeeef32b9c950ywan 296233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Note: Width & height of other-resolution encoders are calculated 297233d2500723e5594f3e7c70896ffeeef32b9c950ywan * from the highest-resolution encoder's size and the corresponding 298233d2500723e5594f3e7c70896ffeeef32b9c950ywan * down_sampling_factor. 299233d2500723e5594f3e7c70896ffeeef32b9c950ywan */ 300233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 301233d2500723e5594f3e7c70896ffeeef32b9c950ywan unsigned int iw = cfg[i-1].g_w*dsf[i-1].den + dsf[i-1].num - 1; 302233d2500723e5594f3e7c70896ffeeef32b9c950ywan unsigned int ih = cfg[i-1].g_h*dsf[i-1].den + dsf[i-1].num - 1; 303233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[i].g_w = iw/dsf[i-1].num; 304233d2500723e5594f3e7c70896ffeeef32b9c950ywan cfg[i].g_h = ih/dsf[i-1].num; 305233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 306233d2500723e5594f3e7c70896ffeeef32b9c950ywan 307233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Make width & height to be multiplier of 2. */ 308233d2500723e5594f3e7c70896ffeeef32b9c950ywan // Should support odd size ??? 309233d2500723e5594f3e7c70896ffeeef32b9c950ywan if((cfg[i].g_w)%2)cfg[i].g_w++; 310233d2500723e5594f3e7c70896ffeeef32b9c950ywan if((cfg[i].g_h)%2)cfg[i].g_h++; 311233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 312233d2500723e5594f3e7c70896ffeeef32b9c950ywan 313233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Allocate image for each encoder */ 314233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=0; i< NUM_ENCODERS; i++) 315233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(!vpx_img_alloc(&raw[i], VPX_IMG_FMT_I420, cfg[i].g_w, cfg[i].g_h, 32)) 316233d2500723e5594f3e7c70896ffeeef32b9c950ywan die("Failed to allocate image", cfg[i].g_w, cfg[i].g_h); 317233d2500723e5594f3e7c70896ffeeef32b9c950ywan 318233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (raw[0].stride[VPX_PLANE_Y] == raw[0].d_w) 319233d2500723e5594f3e7c70896ffeeef32b9c950ywan read_frame_p = read_frame; 320233d2500723e5594f3e7c70896ffeeef32b9c950ywan else 321233d2500723e5594f3e7c70896ffeeef32b9c950ywan read_frame_p = read_frame_by_row; 322233d2500723e5594f3e7c70896ffeeef32b9c950ywan 323233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=0; i< NUM_ENCODERS; i++) 324233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(outfile[i]) 325233d2500723e5594f3e7c70896ffeeef32b9c950ywan write_ivf_file_header(outfile[i], &cfg[i], 0); 326233d2500723e5594f3e7c70896ffeeef32b9c950ywan 327233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Initialize multi-encoder */ 328233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_enc_init_multi(&codec[0], interface, &cfg[0], NUM_ENCODERS, 329233d2500723e5594f3e7c70896ffeeef32b9c950ywan (show_psnr ? VPX_CODEC_USE_PSNR : 0), &dsf[0])) 330233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[0], "Failed to initialize encoder"); 331233d2500723e5594f3e7c70896ffeeef32b9c950ywan 332233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* The extra encoding configuration parameters can be set as follows. */ 333233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Set encoding speed */ 334233d2500723e5594f3e7c70896ffeeef32b9c950ywan for ( i=0; i<NUM_ENCODERS; i++) 335233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 336233d2500723e5594f3e7c70896ffeeef32b9c950ywan int speed = -6; 337233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_control(&codec[i], VP8E_SET_CPUUSED, speed)) 338233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[i], "Failed to set cpu_used"); 339233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 340233d2500723e5594f3e7c70896ffeeef32b9c950ywan 341233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Set static threshold. */ 342233d2500723e5594f3e7c70896ffeeef32b9c950ywan for ( i=0; i<NUM_ENCODERS; i++) 343233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 344233d2500723e5594f3e7c70896ffeeef32b9c950ywan unsigned int static_thresh = 1; 345233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_control(&codec[i], VP8E_SET_STATIC_THRESHOLD, static_thresh)) 346233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[i], "Failed to set static threshold"); 347233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 348233d2500723e5594f3e7c70896ffeeef32b9c950ywan 349233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Set NOISE_SENSITIVITY to do TEMPORAL_DENOISING */ 350233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Enable denoising for the highest-resolution encoder. */ 351233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_control(&codec[0], VP8E_SET_NOISE_SENSITIVITY, 1)) 352233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[0], "Failed to set noise_sensitivity"); 353233d2500723e5594f3e7c70896ffeeef32b9c950ywan for ( i=1; i< NUM_ENCODERS; i++) 354233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 355233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_control(&codec[i], VP8E_SET_NOISE_SENSITIVITY, 0)) 356233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[i], "Failed to set noise_sensitivity"); 357233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 358233d2500723e5594f3e7c70896ffeeef32b9c950ywan 359233d2500723e5594f3e7c70896ffeeef32b9c950ywan 360233d2500723e5594f3e7c70896ffeeef32b9c950ywan frame_avail = 1; 361233d2500723e5594f3e7c70896ffeeef32b9c950ywan got_data = 0; 362233d2500723e5594f3e7c70896ffeeef32b9c950ywan 363233d2500723e5594f3e7c70896ffeeef32b9c950ywan while(frame_avail || got_data) 364233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 365233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_codec_iter_t iter[NUM_ENCODERS]={NULL}; 366233d2500723e5594f3e7c70896ffeeef32b9c950ywan const vpx_codec_cx_pkt_t *pkt[NUM_ENCODERS]; 367233d2500723e5594f3e7c70896ffeeef32b9c950ywan 368233d2500723e5594f3e7c70896ffeeef32b9c950ywan flags = 0; 369233d2500723e5594f3e7c70896ffeeef32b9c950ywan frame_avail = read_frame_p(infile, &raw[0]); 370233d2500723e5594f3e7c70896ffeeef32b9c950ywan 371233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(frame_avail) 372233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 373233d2500723e5594f3e7c70896ffeeef32b9c950ywan for ( i=1; i<NUM_ENCODERS; i++) 374233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 375233d2500723e5594f3e7c70896ffeeef32b9c950ywan /*Scale the image down a number of times by downsampling factor*/ 376233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* FilterMode 1 or 2 give better psnr than FilterMode 0. */ 377233d2500723e5594f3e7c70896ffeeef32b9c950ywan I420Scale(raw[i-1].planes[VPX_PLANE_Y], raw[i-1].stride[VPX_PLANE_Y], 378233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i-1].planes[VPX_PLANE_U], raw[i-1].stride[VPX_PLANE_U], 379233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i-1].planes[VPX_PLANE_V], raw[i-1].stride[VPX_PLANE_V], 380233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i-1].d_w, raw[i-1].d_h, 381233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i].planes[VPX_PLANE_Y], raw[i].stride[VPX_PLANE_Y], 382233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i].planes[VPX_PLANE_U], raw[i].stride[VPX_PLANE_U], 383233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i].planes[VPX_PLANE_V], raw[i].stride[VPX_PLANE_V], 384233d2500723e5594f3e7c70896ffeeef32b9c950ywan raw[i].d_w, raw[i].d_h, 1); 385233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 386233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 387233d2500723e5594f3e7c70896ffeeef32b9c950ywan 388233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Encode each frame at multi-levels */ 389233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_encode(&codec[0], frame_avail? &raw[0] : NULL, 390233d2500723e5594f3e7c70896ffeeef32b9c950ywan frame_cnt, 1, flags, arg_deadline)) 391233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[0], "Failed to encode frame"); 392233d2500723e5594f3e7c70896ffeeef32b9c950ywan 393233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=NUM_ENCODERS-1; i>=0 ; i--) 394233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 395233d2500723e5594f3e7c70896ffeeef32b9c950ywan got_data = 0; 396233d2500723e5594f3e7c70896ffeeef32b9c950ywan 397233d2500723e5594f3e7c70896ffeeef32b9c950ywan while( (pkt[i] = vpx_codec_get_cx_data(&codec[i], &iter[i])) ) 398233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 399233d2500723e5594f3e7c70896ffeeef32b9c950ywan got_data = 1; 400233d2500723e5594f3e7c70896ffeeef32b9c950ywan switch(pkt[i]->kind) { 401233d2500723e5594f3e7c70896ffeeef32b9c950ywan case VPX_CODEC_CX_FRAME_PKT: 402233d2500723e5594f3e7c70896ffeeef32b9c950ywan write_ivf_frame_header(outfile[i], pkt[i]); 403233d2500723e5594f3e7c70896ffeeef32b9c950ywan (void) fwrite(pkt[i]->data.frame.buf, 1, 404233d2500723e5594f3e7c70896ffeeef32b9c950ywan pkt[i]->data.frame.sz, outfile[i]); 405233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 406233d2500723e5594f3e7c70896ffeeef32b9c950ywan case VPX_CODEC_PSNR_PKT: 407233d2500723e5594f3e7c70896ffeeef32b9c950ywan if (show_psnr) 408233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 409233d2500723e5594f3e7c70896ffeeef32b9c950ywan int j; 410233d2500723e5594f3e7c70896ffeeef32b9c950ywan 411233d2500723e5594f3e7c70896ffeeef32b9c950ywan psnr_sse_total[i] += pkt[i]->data.psnr.sse[0]; 412233d2500723e5594f3e7c70896ffeeef32b9c950ywan psnr_samples_total[i] += pkt[i]->data.psnr.samples[0]; 413233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (j = 0; j < 4; j++) 414233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 415233d2500723e5594f3e7c70896ffeeef32b9c950ywan //fprintf(stderr, "%.3lf ", pkt[i]->data.psnr.psnr[j]); 416233d2500723e5594f3e7c70896ffeeef32b9c950ywan psnr_totals[i][j] += pkt[i]->data.psnr.psnr[j]; 417233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 418233d2500723e5594f3e7c70896ffeeef32b9c950ywan psnr_count[i]++; 419233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 420233d2500723e5594f3e7c70896ffeeef32b9c950ywan 421233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 422233d2500723e5594f3e7c70896ffeeef32b9c950ywan default: 423233d2500723e5594f3e7c70896ffeeef32b9c950ywan break; 424233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 425233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf(pkt[i]->kind == VPX_CODEC_CX_FRAME_PKT 426233d2500723e5594f3e7c70896ffeeef32b9c950ywan && (pkt[i]->data.frame.flags & VPX_FRAME_IS_KEY)? "K":"."); 427233d2500723e5594f3e7c70896ffeeef32b9c950ywan fflush(stdout); 428233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 429233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 430233d2500723e5594f3e7c70896ffeeef32b9c950ywan frame_cnt++; 431233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 432233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("\n"); 433233d2500723e5594f3e7c70896ffeeef32b9c950ywan 434233d2500723e5594f3e7c70896ffeeef32b9c950ywan fclose(infile); 435233d2500723e5594f3e7c70896ffeeef32b9c950ywan 436233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("Processed %ld frames.\n",(long int)frame_cnt-1); 437233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (i=0; i< NUM_ENCODERS; i++) 438233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 439233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Calculate PSNR and print it out */ 440233d2500723e5594f3e7c70896ffeeef32b9c950ywan if ( (show_psnr) && (psnr_count[i]>0) ) 441233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 442233d2500723e5594f3e7c70896ffeeef32b9c950ywan int j; 443233d2500723e5594f3e7c70896ffeeef32b9c950ywan double ovpsnr = sse_to_psnr(psnr_samples_total[i], 255.0, 444233d2500723e5594f3e7c70896ffeeef32b9c950ywan psnr_sse_total[i]); 445233d2500723e5594f3e7c70896ffeeef32b9c950ywan 446233d2500723e5594f3e7c70896ffeeef32b9c950ywan fprintf(stderr, "\n ENC%d PSNR (Overall/Avg/Y/U/V)", i); 447233d2500723e5594f3e7c70896ffeeef32b9c950ywan 448233d2500723e5594f3e7c70896ffeeef32b9c950ywan fprintf(stderr, " %.3lf", ovpsnr); 449233d2500723e5594f3e7c70896ffeeef32b9c950ywan for (j = 0; j < 4; j++) 450233d2500723e5594f3e7c70896ffeeef32b9c950ywan { 451233d2500723e5594f3e7c70896ffeeef32b9c950ywan fprintf(stderr, " %.3lf", psnr_totals[i][j]/psnr_count[i]); 452233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 453233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 454233d2500723e5594f3e7c70896ffeeef32b9c950ywan 455233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(vpx_codec_destroy(&codec[i])) 456233d2500723e5594f3e7c70896ffeeef32b9c950ywan die_codec(&codec[i], "Failed to destroy codec"); 457233d2500723e5594f3e7c70896ffeeef32b9c950ywan 458233d2500723e5594f3e7c70896ffeeef32b9c950ywan vpx_img_free(&raw[i]); 459233d2500723e5594f3e7c70896ffeeef32b9c950ywan 460233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(!outfile[i]) 461233d2500723e5594f3e7c70896ffeeef32b9c950ywan continue; 462233d2500723e5594f3e7c70896ffeeef32b9c950ywan 463233d2500723e5594f3e7c70896ffeeef32b9c950ywan /* Try to rewrite the file header with the actual frame count */ 464233d2500723e5594f3e7c70896ffeeef32b9c950ywan if(!fseek(outfile[i], 0, SEEK_SET)) 465233d2500723e5594f3e7c70896ffeeef32b9c950ywan write_ivf_file_header(outfile[i], &cfg[i], frame_cnt-1); 466233d2500723e5594f3e7c70896ffeeef32b9c950ywan fclose(outfile[i]); 467233d2500723e5594f3e7c70896ffeeef32b9c950ywan } 468233d2500723e5594f3e7c70896ffeeef32b9c950ywan printf("\n"); 469233d2500723e5594f3e7c70896ffeeef32b9c950ywan 470233d2500723e5594f3e7c70896ffeeef32b9c950ywan return EXIT_SUCCESS; 471233d2500723e5594f3e7c70896ffeeef32b9c950ywan} 472