2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
14 // This is an example of a two pass encoder loop. It takes an input file in
15 // YV12 format, passes it through the encoder twice, and writes the compressed
16 // frames to disk in IVF format. It builds upon the simple_encoder example.
20 // Twopass mode needs to track the current pass number and the buffer of
21 // statistics packets.
23 // Updating The Configuration
24 // ---------------------------------
25 // In two pass mode, the configuration has to be updated on each pass. The
26 // statistics buffer is passed on the last pass.
30 // Encoding a frame in two pass mode is identical to the simple encoder
31 // example. To increase the quality while sacrificing encoding speed,
32 // VPX_DL_BEST_QUALITY can be used in place of VPX_DL_GOOD_QUALITY.
34 // Processing Statistics Packets
35 // -----------------------------
36 // Each packet of type `VPX_CODEC_CX_FRAME_PKT` contains the encoded data
37 // for this frame. We write a IVF frame header, followed by the raw data.
40 // Pass Progress Reporting
41 // -----------------------------
42 // It's sometimes helpful to see when each pass completes.
46 // -----------------------------
47 // Destruction of the encoder instance must be done on each pass. The
48 // raw image should be destroyed at the end as usual.
54 #include "vpx/vpx_encoder.h"
56 #include "../tools_common.h"
57 #include "../video_writer.h"
59 static const char *exec_name
;
61 void usage_exit(void) {
62 fprintf(stderr
, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
67 static int get_frame_stats(vpx_codec_ctx_t
*ctx
,
68 const vpx_image_t
*img
,
70 unsigned int duration
,
71 vpx_enc_frame_flags_t flags
,
72 unsigned int deadline
,
73 vpx_fixed_buf_t
*stats
) {
75 vpx_codec_iter_t iter
= NULL
;
76 const vpx_codec_cx_pkt_t
*pkt
= NULL
;
77 const vpx_codec_err_t res
= vpx_codec_encode(ctx
, img
, pts
, duration
, flags
,
79 if (res
!= VPX_CODEC_OK
)
80 die_codec(ctx
, "Failed to get frame stats.");
82 while ((pkt
= vpx_codec_get_cx_data(ctx
, &iter
)) != NULL
) {
85 if (pkt
->kind
== VPX_CODEC_STATS_PKT
) {
86 const uint8_t *const pkt_buf
= pkt
->data
.twopass_stats
.buf
;
87 const size_t pkt_size
= pkt
->data
.twopass_stats
.sz
;
88 stats
->buf
= realloc(stats
->buf
, stats
->sz
+ pkt_size
);
89 memcpy((uint8_t *)stats
->buf
+ stats
->sz
, pkt_buf
, pkt_size
);
90 stats
->sz
+= pkt_size
;
97 static int encode_frame(vpx_codec_ctx_t
*ctx
,
98 const vpx_image_t
*img
,
100 unsigned int duration
,
101 vpx_enc_frame_flags_t flags
,
102 unsigned int deadline
,
103 VpxVideoWriter
*writer
) {
105 vpx_codec_iter_t iter
= NULL
;
106 const vpx_codec_cx_pkt_t
*pkt
= NULL
;
107 const vpx_codec_err_t res
= vpx_codec_encode(ctx
, img
, pts
, duration
, flags
,
109 if (res
!= VPX_CODEC_OK
)
110 die_codec(ctx
, "Failed to encode frame.");
112 while ((pkt
= vpx_codec_get_cx_data(ctx
, &iter
)) != NULL
) {
114 if (pkt
->kind
== VPX_CODEC_CX_FRAME_PKT
) {
115 const int keyframe
= (pkt
->data
.frame
.flags
& VPX_FRAME_IS_KEY
) != 0;
117 if (!vpx_video_writer_write_frame(writer
, pkt
->data
.frame
.buf
,
119 pkt
->data
.frame
.pts
))
120 die_codec(ctx
, "Failed to write compressed frame.");
121 printf(keyframe
? "K" : ".");
129 static vpx_fixed_buf_t
pass0(vpx_image_t
*raw
,
131 const VpxInterface
*encoder
,
132 const vpx_codec_enc_cfg_t
*cfg
) {
133 vpx_codec_ctx_t codec
;
135 vpx_fixed_buf_t stats
= {NULL
, 0};
137 if (vpx_codec_enc_init(&codec
, encoder
->codec_interface(), cfg
, 0))
138 die_codec(&codec
, "Failed to initialize encoder");
140 // Calculate frame statistics.
141 while (vpx_img_read(raw
, infile
)) {
143 get_frame_stats(&codec
, raw
, frame_count
, 1, 0, VPX_DL_GOOD_QUALITY
,
148 while (get_frame_stats(&codec
, NULL
, frame_count
, 1, 0,
149 VPX_DL_GOOD_QUALITY
, &stats
)) {}
151 printf("Pass 0 complete. Processed %d frames.\n", frame_count
);
152 if (vpx_codec_destroy(&codec
))
153 die_codec(&codec
, "Failed to destroy codec.");
158 static void pass1(vpx_image_t
*raw
,
160 const char *outfile_name
,
161 const VpxInterface
*encoder
,
162 const vpx_codec_enc_cfg_t
*cfg
) {
163 VpxVideoInfo info
= {
167 {cfg
->g_timebase
.num
, cfg
->g_timebase
.den
}
169 VpxVideoWriter
*writer
= NULL
;
170 vpx_codec_ctx_t codec
;
173 writer
= vpx_video_writer_open(outfile_name
, kContainerIVF
, &info
);
175 die("Failed to open %s for writing", outfile_name
);
177 if (vpx_codec_enc_init(&codec
, encoder
->codec_interface(), cfg
, 0))
178 die_codec(&codec
, "Failed to initialize encoder");
181 while (vpx_img_read(raw
, infile
)) {
183 encode_frame(&codec
, raw
, frame_count
, 1, 0, VPX_DL_GOOD_QUALITY
, writer
);
187 while (encode_frame(&codec
, NULL
, -1, 1, 0, VPX_DL_GOOD_QUALITY
, writer
)) {}
191 if (vpx_codec_destroy(&codec
))
192 die_codec(&codec
, "Failed to destroy codec.");
194 vpx_video_writer_close(writer
);
196 printf("Pass 1 complete. Processed %d frames.\n", frame_count
);
199 int main(int argc
, char **argv
) {
202 vpx_codec_ctx_t codec
;
203 vpx_codec_enc_cfg_t cfg
;
206 vpx_fixed_buf_t stats
;
208 const VpxInterface
*encoder
= NULL
;
209 const int fps
= 30; // TODO(dkovalev) add command line argument
210 const int bitrate
= 200; // kbit/s TODO(dkovalev) add command line argument
211 const char *const codec_arg
= argv
[1];
212 const char *const width_arg
= argv
[2];
213 const char *const height_arg
= argv
[3];
214 const char *const infile_arg
= argv
[4];
215 const char *const outfile_arg
= argv
[5];
219 die("Invalid number of arguments.");
221 encoder
= get_vpx_encoder_by_name(codec_arg
);
223 die("Unsupported codec.");
225 w
= strtol(width_arg
, NULL
, 0);
226 h
= strtol(height_arg
, NULL
, 0);
228 if (w
<= 0 || h
<= 0 || (w
% 2) != 0 || (h
% 2) != 0)
229 die("Invalid frame size: %dx%d", w
, h
);
231 if (!vpx_img_alloc(&raw
, VPX_IMG_FMT_I420
, w
, h
, 1))
232 die("Failed to allocate image", w
, h
);
234 printf("Using %s\n", vpx_codec_iface_name(encoder
->codec_interface()));
237 res
= vpx_codec_enc_config_default(encoder
->codec_interface(), &cfg
, 0);
239 die_codec(&codec
, "Failed to get default codec config.");
243 cfg
.g_timebase
.num
= 1;
244 cfg
.g_timebase
.den
= fps
;
245 cfg
.rc_target_bitrate
= bitrate
;
247 if (!(infile
= fopen(infile_arg
, "rb")))
248 die("Failed to open %s for reading", infile_arg
);
251 cfg
.g_pass
= VPX_RC_FIRST_PASS
;
252 stats
= pass0(&raw
, infile
, encoder
, &cfg
);
256 cfg
.g_pass
= VPX_RC_LAST_PASS
;
257 cfg
.rc_twopass_stats_in
= stats
;
258 pass1(&raw
, infile
, outfile_arg
, encoder
, &cfg
);