blob: 654b1e95ff9c5f0e06ee60ac3efda1a97f2486d0 [file] [log] [blame]
Dmitry Kovalev50fa5852014-01-07 15:15:25 -08001/*
Yaowu Xu9c01aa12016-09-01 14:32:49 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Dmitry Kovalev50fa5852014-01-07 15:15:25 -08003 *
Yaowu Xu9c01aa12016-09-01 14:32:49 -07004 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080010 */
11
Yaowu Xu9c01aa12016-09-01 14:32:49 -070012// AOM Set Active and ROI Maps
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080013// ===========================
14//
Yaowu Xu9c01aa12016-09-01 14:32:49 -070015// This is an example demonstrating how to control the AOM encoder's
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080016// ROI and Active maps.
17//
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.
21//
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
24// macroblock.
25//
26//
27// Configuration
28// -------------
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.
33//
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.
37//
38// The active map is cleared on frame 44.
39//
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.
44
Jim Bankoski812506b2014-08-19 14:56:09 -070045#include <assert.h>
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080046#include <stdio.h>
47#include <stdlib.h>
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080048#include <string.h>
Dmitry Kovalev8837b022014-02-13 14:18:05 -080049
Yaowu Xuf883b422016-08-30 14:01:10 -070050#include "aom/aomcx.h"
51#include "aom/aom_encoder.h"
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080052
Tom Finegan9e96bdc2015-02-04 16:11:57 -080053#include "../tools_common.h"
54#include "../video_writer.h"
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080055
Dmitry Kovalev8837b022014-02-13 14:18:05 -080056static const char *exec_name;
57
James Zern59e7a472015-05-09 10:33:26 -070058void usage_exit(void) {
Alex Converse61ecd7f2014-03-10 16:13:49 -070059 fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
60 exec_name);
Dmitry Kovalev8837b022014-02-13 14:18:05 -080061 exit(EXIT_FAILURE);
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080062}
63
Yaowu Xuf883b422016-08-30 14:01:10 -070064static void set_active_map(const aom_codec_enc_cfg_t *cfg,
65 aom_codec_ctx_t *codec) {
Tom Finegan560119c2014-02-19 16:13:15 -080066 unsigned int i;
Yaowu Xuf883b422016-08-30 14:01:10 -070067 aom_active_map_t map = { 0, 0, 0 };
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080068
Alex Converseb528d492014-03-10 16:08:58 -070069 map.rows = (cfg->g_h + 15) / 16;
70 map.cols = (cfg->g_w + 15) / 16;
Dmitry Kovalev8837b022014-02-13 14:18:05 -080071
72 map.active_map = (uint8_t *)malloc(map.rows * map.cols);
clang-format397d9642016-08-08 18:51:16 -070073 for (i = 0; i < map.rows * map.cols; ++i) map.active_map[i] = i % 2;
Dmitry Kovalev8837b022014-02-13 14:18:05 -080074
Yaowu Xuf883b422016-08-30 14:01:10 -070075 if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map))
Dmitry Kovalev8837b022014-02-13 14:18:05 -080076 die_codec(codec, "Failed to set active map");
77
78 free(map.active_map);
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080079}
80
Yaowu Xuf883b422016-08-30 14:01:10 -070081static void unset_active_map(const aom_codec_enc_cfg_t *cfg,
82 aom_codec_ctx_t *codec) {
83 aom_active_map_t map = { 0, 0, 0 };
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080084
Alex Converseb528d492014-03-10 16:08:58 -070085 map.rows = (cfg->g_h + 15) / 16;
86 map.cols = (cfg->g_w + 15) / 16;
Dmitry Kovalev8837b022014-02-13 14:18:05 -080087 map.active_map = NULL;
88
Yaowu Xuf883b422016-08-30 14:01:10 -070089 if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map))
Dmitry Kovalev8837b022014-02-13 14:18:05 -080090 die_codec(codec, "Failed to set active map");
Dmitry Kovalev50fa5852014-01-07 15:15:25 -080091}
92
Yaowu Xuf883b422016-08-30 14:01:10 -070093static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img,
94 int frame_index, AvxVideoWriter *writer) {
Dmitry Kovaleva8e674d2014-08-15 17:15:17 -070095 int got_pkts = 0;
Yaowu Xuf883b422016-08-30 14:01:10 -070096 aom_codec_iter_t iter = NULL;
97 const aom_codec_cx_pkt_t *pkt = NULL;
98 const aom_codec_err_t res =
99 aom_codec_encode(codec, img, frame_index, 1, 0, AOM_DL_GOOD_QUALITY);
100 if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame");
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800101
Yaowu Xuf883b422016-08-30 14:01:10 -0700102 while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) {
Dmitry Kovaleva8e674d2014-08-15 17:15:17 -0700103 got_pkts = 1;
104
Yaowu Xuf883b422016-08-30 14:01:10 -0700105 if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
106 const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0;
107 if (!aom_video_writer_write_frame(writer, pkt->data.frame.buf,
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800108 pkt->data.frame.sz,
109 pkt->data.frame.pts)) {
110 die_codec(codec, "Failed to write compressed frame");
111 }
112
113 printf(keyframe ? "K" : ".");
114 fflush(stdout);
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800115 }
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800116 }
Dmitry Kovaleva8e674d2014-08-15 17:15:17 -0700117
118 return got_pkts;
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800119}
120
121int main(int argc, char **argv) {
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800122 FILE *infile = NULL;
Yaowu Xuf883b422016-08-30 14:01:10 -0700123 aom_codec_ctx_t codec;
124 aom_codec_enc_cfg_t cfg;
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800125 int frame_count = 0;
Yaowu Xuf883b422016-08-30 14:01:10 -0700126 aom_image_t raw;
127 aom_codec_err_t res;
128 AvxVideoInfo info;
129 AvxVideoWriter *writer = NULL;
130 const AvxInterface *encoder = NULL;
clang-format397d9642016-08-08 18:51:16 -0700131 const int fps = 2; // TODO(dkovalev) add command line argument
Alex Converseb528d492014-03-10 16:08:58 -0700132 const double bits_per_pixel_per_frame = 0.067;
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800133
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800134 exec_name = argv[0];
clang-format397d9642016-08-08 18:51:16 -0700135 if (argc != 6) die("Invalid number of arguments");
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800136
Yaowu Xu70835602014-05-13 09:32:18 -0700137 memset(&info, 0, sizeof(info));
138
Yaowu Xuf883b422016-08-30 14:01:10 -0700139 encoder = get_aom_encoder_by_name(argv[1]);
Jim Bankoski812506b2014-08-19 14:56:09 -0700140 if (encoder == NULL) {
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800141 die("Unsupported codec.");
Jim Bankoski812506b2014-08-19 14:56:09 -0700142 }
143 assert(encoder != NULL);
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800144 info.codec_fourcc = encoder->fourcc;
Alex Converse61ecd7f2014-03-10 16:13:49 -0700145 info.frame_width = strtol(argv[2], NULL, 0);
146 info.frame_height = strtol(argv[3], NULL, 0);
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800147 info.time_base.numerator = 1;
148 info.time_base.denominator = fps;
149
clang-format397d9642016-08-08 18:51:16 -0700150 if (info.frame_width <= 0 || info.frame_height <= 0 ||
151 (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800152 die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
153 }
154
Yaowu Xuf883b422016-08-30 14:01:10 -0700155 if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, info.frame_width,
clang-format397d9642016-08-08 18:51:16 -0700156 info.frame_height, 1)) {
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800157 die("Failed to allocate image.");
158 }
159
Yaowu Xuf883b422016-08-30 14:01:10 -0700160 printf("Using %s\n", aom_codec_iface_name(encoder->codec_interface()));
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800161
Yaowu Xuf883b422016-08-30 14:01:10 -0700162 res = aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
clang-format397d9642016-08-08 18:51:16 -0700163 if (res) die_codec(&codec, "Failed to get default codec config.");
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800164
165 cfg.g_w = info.frame_width;
166 cfg.g_h = info.frame_height;
167 cfg.g_timebase.num = info.time_base.numerator;
168 cfg.g_timebase.den = info.time_base.denominator;
clang-format397d9642016-08-08 18:51:16 -0700169 cfg.rc_target_bitrate =
170 (unsigned int)(bits_per_pixel_per_frame * cfg.g_w * cfg.g_h * fps / 1000);
Alex Converse61ecd7f2014-03-10 16:13:49 -0700171 cfg.g_lag_in_frames = 0;
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800172
Yaowu Xuf883b422016-08-30 14:01:10 -0700173 writer = aom_video_writer_open(argv[5], kContainerIVF, &info);
clang-format397d9642016-08-08 18:51:16 -0700174 if (!writer) die("Failed to open %s for writing.", argv[5]);
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800175
Alex Converse61ecd7f2014-03-10 16:13:49 -0700176 if (!(infile = fopen(argv[4], "rb")))
177 die("Failed to open %s for reading.", argv[4]);
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800178
Yaowu Xuf883b422016-08-30 14:01:10 -0700179 if (aom_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800180 die_codec(&codec, "Failed to initialize encoder");
181
Dmitry Kovaleva8e674d2014-08-15 17:15:17 -0700182 // Encode frames.
Yaowu Xuf883b422016-08-30 14:01:10 -0700183 while (aom_img_read(&raw, infile)) {
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800184 ++frame_count;
185
Jim Bankoskia7a39092016-05-20 06:25:40 -0700186 if (frame_count == 33) {
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800187 set_active_map(&cfg, &codec);
188 } else if (frame_count == 44) {
189 unset_active_map(&cfg, &codec);
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800190 }
191
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800192 encode_frame(&codec, &raw, frame_count, writer);
193 }
Dmitry Kovaleva8e674d2014-08-15 17:15:17 -0700194
195 // Flush encoder.
clang-format397d9642016-08-08 18:51:16 -0700196 while (encode_frame(&codec, NULL, -1, writer)) {
197 }
Dmitry Kovaleva8e674d2014-08-15 17:15:17 -0700198
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800199 printf("\n");
200 fclose(infile);
201 printf("Processed %d frames.\n", frame_count);
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800202
Yaowu Xuf883b422016-08-30 14:01:10 -0700203 aom_img_free(&raw);
204 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800205
Yaowu Xuf883b422016-08-30 14:01:10 -0700206 aom_video_writer_close(writer);
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800207
Dmitry Kovalev8837b022014-02-13 14:18:05 -0800208 return EXIT_SUCCESS;
Dmitry Kovalev50fa5852014-01-07 15:15:25 -0800209}