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