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.
12 // VP8 Set Active and ROI Maps
13 // ===========================
15 // This is an example demonstrating how to control the VP8 encoder's
16 // ROI and Active maps.
18 // ROI (Reigon of Interest) maps are a way for the application to assign
19 // each macroblock in the image to a region, and then set quantizer and
20 // filtering parameters on that image.
22 // Active maps are a way for the application to specify on a
23 // macroblock-by-macroblock basis whether there is any activity in that
29 // An ROI map is set on frame 22. If the width of the image in macroblocks
30 // is evenly divisble by 4, then the output will appear to have distinct
31 // columns, where the quantizer, loopfilter, and static threshold differ
32 // from column to column.
34 // An active map is set on frame 33. If the width of the image in macroblocks
35 // is evenly divisble by 4, then the output will appear to have distinct
36 // columns, where one column will have motion and the next will not.
38 // The active map is cleared on frame 44.
40 // Observing The Effects
41 // ---------------------
42 // Use the `simple_decoder` example to decode this sample, and observe
43 // the change in the image at frames 22, 33, and 44.
49 #define VPX_CODEC_DISABLE_COMPAT 1
50 #include "vpx/vpx_encoder.h"
51 #include "vpx/vp8cx.h"
52 #define interface (vpx_codec_vp8_cx())
53 #define fourcc 0x30385056
55 #define IVF_FILE_HDR_SZ (32)
56 #define IVF_FRAME_HDR_SZ (12)
58 static void mem_put_le16(char *mem, unsigned int val) {
63 static void mem_put_le32(char *mem, unsigned int val) {
70 static void die(const char *fmt, ...) {
75 if(fmt[strlen(fmt)-1] != '\n')
80 static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
81 const char *detail = vpx_codec_error_detail(ctx);
83 printf("%s: %s\n", s, vpx_codec_error(ctx));
85 printf(" %s\n",detail);
89 static int read_frame(FILE *f, vpx_image_t *img) {
90 size_t nbytes, to_read;
93 to_read = img->w*img->h*3/2;
94 nbytes = fread(img->planes[0], 1, to_read, f);
95 if(nbytes != to_read) {
98 printf("Warning: Read partial frame. Check your width & height!\n");
103 static void write_ivf_file_header(FILE *outfile,
104 const vpx_codec_enc_cfg_t *cfg,
108 if(cfg->g_pass != VPX_RC_ONE_PASS && cfg->g_pass != VPX_RC_LAST_PASS)
114 mem_put_le16(header+4, 0); /* version */
115 mem_put_le16(header+6, 32); /* headersize */
116 mem_put_le32(header+8, fourcc); /* headersize */
117 mem_put_le16(header+12, cfg->g_w); /* width */
118 mem_put_le16(header+14, cfg->g_h); /* height */
119 mem_put_le32(header+16, cfg->g_timebase.den); /* rate */
120 mem_put_le32(header+20, cfg->g_timebase.num); /* scale */
121 mem_put_le32(header+24, frame_cnt); /* length */
122 mem_put_le32(header+28, 0); /* unused */
124 (void) fwrite(header, 1, 32, outfile);
128 static void write_ivf_frame_header(FILE *outfile,
129 const vpx_codec_cx_pkt_t *pkt)
134 if(pkt->kind != VPX_CODEC_CX_FRAME_PKT)
137 pts = pkt->data.frame.pts;
138 mem_put_le32(header, pkt->data.frame.sz);
139 mem_put_le32(header+4, pts&0xFFFFFFFF);
140 mem_put_le32(header+8, pts >> 32);
142 (void) fwrite(header, 1, 12, outfile);
145 int main(int argc, char **argv) {
146 FILE *infile, *outfile;
147 vpx_codec_ctx_t codec;
148 vpx_codec_enc_cfg_t cfg;
160 die("Usage: %s <width> <height> <infile> <outfile>\n", argv[0]);
161 width = strtol(argv[1], NULL, 0);
162 height = strtol(argv[2], NULL, 0);
163 if(width < 16 || width%2 || height <16 || height%2)
164 die("Invalid resolution: %ldx%ld", width, height);
165 if(!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, width, height, 1))
166 die("Faile to allocate image", width, height);
167 if(!(outfile = fopen(argv[4], "wb")))
168 die("Failed to open %s for writing", argv[4]);
170 printf("Using %s\n",vpx_codec_iface_name(interface));
172 /* Populate encoder configuration */
173 res = vpx_codec_enc_config_default(interface, &cfg, 0);
175 printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
179 /* Update the default configuration with our settings */
180 cfg.rc_target_bitrate = width * height * cfg.rc_target_bitrate
185 write_ivf_file_header(outfile, &cfg, 0);
188 /* Open input file for this encoding pass */
189 if(!(infile = fopen(argv[3], "rb")))
190 die("Failed to open %s for reading", argv[3]);
192 /* Initialize codec */
193 if(vpx_codec_enc_init(&codec, interface, &cfg, 0))
194 die_codec(&codec, "Failed to initialize encoder");
198 while(frame_avail || got_data) {
199 vpx_codec_iter_t iter = NULL;
200 const vpx_codec_cx_pkt_t *pkt;
202 if(frame_cnt + 1 == 22) {
206 roi.rows = cfg.g_h/16;
207 roi.cols = cfg.g_w/16;
219 roi.static_threshold[0] = 1500;
220 roi.static_threshold[1] = 1000;
221 roi.static_threshold[2] = 500;
222 roi.static_threshold[3] = 0;
224 /* generate an ROI map for example */
225 roi.roi_map = malloc(roi.rows * roi.cols);
226 for(i=0;i<roi.rows*roi.cols;i++)
227 roi.roi_map[i] = i & 3;
229 if(vpx_codec_control(&codec, VP8E_SET_ROI_MAP, &roi))
230 die_codec(&codec, "Failed to set ROI map");
233 } else if(frame_cnt + 1 == 33) {
234 vpx_active_map_t active;
237 active.rows = cfg.g_h/16;
238 active.cols = cfg.g_w/16;
240 /* generate active map for example */
241 active.active_map = malloc(active.rows * active.cols);
242 for(i=0;i<active.rows*active.cols;i++)
243 active.active_map[i] = i & 1;
245 if(vpx_codec_control(&codec, VP8E_SET_ACTIVEMAP, &active))
246 die_codec(&codec, "Failed to set active map");
248 free(active.active_map);
249 } else if(frame_cnt + 1 == 44) {
250 vpx_active_map_t active;
252 active.rows = cfg.g_h/16;
253 active.cols = cfg.g_w/16;
255 /* pass in null map to disable active_map*/
256 active.active_map = NULL;
258 if(vpx_codec_control(&codec, VP8E_SET_ACTIVEMAP, &active))
259 die_codec(&codec, "Failed to set active map");
261 frame_avail = read_frame(infile, &raw);
262 if(vpx_codec_encode(&codec, frame_avail? &raw : NULL, frame_cnt,
263 1, flags, VPX_DL_REALTIME))
264 die_codec(&codec, "Failed to encode frame");
266 while( (pkt = vpx_codec_get_cx_data(&codec, &iter)) ) {
269 case VPX_CODEC_CX_FRAME_PKT:
270 write_ivf_frame_header(outfile, pkt);
271 (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz,
277 printf(pkt->kind == VPX_CODEC_CX_FRAME_PKT
278 && (pkt->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
286 printf("Processed %d frames.\n",frame_cnt-1);
288 if(vpx_codec_destroy(&codec))
289 die_codec(&codec, "Failed to destroy codec");
291 /* Try to rewrite the file header with the actual frame count */
292 if(!fseek(outfile, 0, SEEK_SET))
293 write_ivf_file_header(outfile, &cfg, frame_cnt-1);