Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
| 3 | * |
| 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. |
| 9 | */ |
| 10 | |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 11 | // VP8 Set Active and ROI Maps |
| 12 | // =========================== |
| 13 | // |
| 14 | // This is an example demonstrating how to control the VP8 encoder's |
| 15 | // ROI and Active maps. |
| 16 | // |
| 17 | // ROI (Reigon of Interest) maps are a way for the application to assign |
| 18 | // each macroblock in the image to a region, and then set quantizer and |
| 19 | // filtering parameters on that image. |
| 20 | // |
| 21 | // Active maps are a way for the application to specify on a |
| 22 | // macroblock-by-macroblock basis whether there is any activity in that |
| 23 | // macroblock. |
| 24 | // |
| 25 | // |
| 26 | // Configuration |
| 27 | // ------------- |
| 28 | // An ROI map is set on frame 22. If the width of the image in macroblocks |
| 29 | // is evenly divisble by 4, then the output will appear to have distinct |
| 30 | // columns, where the quantizer, loopfilter, and static threshold differ |
| 31 | // from column to column. |
| 32 | // |
| 33 | // An active map is set on frame 33. If the width of the image in macroblocks |
| 34 | // is evenly divisble by 4, then the output will appear to have distinct |
| 35 | // columns, where one column will have motion and the next will not. |
| 36 | // |
| 37 | // The active map is cleared on frame 44. |
| 38 | // |
| 39 | // Observing The Effects |
| 40 | // --------------------- |
| 41 | // Use the `simple_decoder` example to decode this sample, and observe |
| 42 | // the change in the image at frames 22, 33, and 44. |
| 43 | |
Jim Bankoski | 812506b | 2014-08-19 14:56:09 -0700 | [diff] [blame] | 44 | #include <assert.h> |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 45 | #include <stdio.h> |
| 46 | #include <stdlib.h> |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 47 | #include <string.h> |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 48 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 49 | #include "aom/aomcx.h" |
| 50 | #include "aom/aom_encoder.h" |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 51 | |
Tom Finegan | 9e96bdc | 2015-02-04 16:11:57 -0800 | [diff] [blame] | 52 | #include "../tools_common.h" |
| 53 | #include "../video_writer.h" |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 54 | |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 55 | static const char *exec_name; |
| 56 | |
James Zern | 59e7a47 | 2015-05-09 10:33:26 -0700 | [diff] [blame] | 57 | void usage_exit(void) { |
Alex Converse | 61ecd7f | 2014-03-10 16:13:49 -0700 | [diff] [blame] | 58 | fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n", |
| 59 | exec_name); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 60 | exit(EXIT_FAILURE); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 61 | } |
| 62 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 63 | static void set_roi_map(const aom_codec_enc_cfg_t *cfg, |
| 64 | aom_codec_ctx_t *codec) { |
Tom Finegan | 560119c | 2014-02-19 16:13:15 -0800 | [diff] [blame] | 65 | unsigned int i; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 66 | aom_roi_map_t roi; |
Yaowu Xu | 7083560 | 2014-05-13 09:32:18 -0700 | [diff] [blame] | 67 | memset(&roi, 0, sizeof(roi)); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 68 | |
Alex Converse | b528d49 | 2014-03-10 16:08:58 -0700 | [diff] [blame] | 69 | roi.rows = (cfg->g_h + 15) / 16; |
| 70 | roi.cols = (cfg->g_w + 15) / 16; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 71 | |
| 72 | roi.delta_q[0] = 0; |
| 73 | roi.delta_q[1] = -2; |
| 74 | roi.delta_q[2] = -4; |
| 75 | roi.delta_q[3] = -6; |
| 76 | |
| 77 | roi.delta_lf[0] = 0; |
| 78 | roi.delta_lf[1] = 1; |
| 79 | roi.delta_lf[2] = 2; |
| 80 | roi.delta_lf[3] = 3; |
| 81 | |
| 82 | roi.static_threshold[0] = 1500; |
| 83 | roi.static_threshold[1] = 1000; |
| 84 | roi.static_threshold[2] = 500; |
| 85 | roi.static_threshold[3] = 0; |
| 86 | |
| 87 | roi.roi_map = (uint8_t *)malloc(roi.rows * roi.cols); |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 88 | for (i = 0; i < roi.rows * roi.cols; ++i) roi.roi_map[i] = i % 4; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 89 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 90 | if (aom_codec_control(codec, AOME_SET_ROI_MAP, &roi)) |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 91 | die_codec(codec, "Failed to set ROI map"); |
| 92 | |
| 93 | free(roi.roi_map); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 94 | } |
| 95 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 96 | static void set_active_map(const aom_codec_enc_cfg_t *cfg, |
| 97 | aom_codec_ctx_t *codec) { |
Tom Finegan | 560119c | 2014-02-19 16:13:15 -0800 | [diff] [blame] | 98 | unsigned int i; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 99 | aom_active_map_t map = { 0, 0, 0 }; |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 100 | |
Alex Converse | b528d49 | 2014-03-10 16:08:58 -0700 | [diff] [blame] | 101 | map.rows = (cfg->g_h + 15) / 16; |
| 102 | map.cols = (cfg->g_w + 15) / 16; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 103 | |
| 104 | map.active_map = (uint8_t *)malloc(map.rows * map.cols); |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 105 | for (i = 0; i < map.rows * map.cols; ++i) map.active_map[i] = i % 2; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 106 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 107 | if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map)) |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 108 | die_codec(codec, "Failed to set active map"); |
| 109 | |
| 110 | free(map.active_map); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 111 | } |
| 112 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 113 | static void unset_active_map(const aom_codec_enc_cfg_t *cfg, |
| 114 | aom_codec_ctx_t *codec) { |
| 115 | aom_active_map_t map = { 0, 0, 0 }; |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 116 | |
Alex Converse | b528d49 | 2014-03-10 16:08:58 -0700 | [diff] [blame] | 117 | map.rows = (cfg->g_h + 15) / 16; |
| 118 | map.cols = (cfg->g_w + 15) / 16; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 119 | map.active_map = NULL; |
| 120 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 121 | if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map)) |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 122 | die_codec(codec, "Failed to set active map"); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 123 | } |
| 124 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 125 | static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img, |
| 126 | int frame_index, AvxVideoWriter *writer) { |
Dmitry Kovalev | a8e674d | 2014-08-15 17:15:17 -0700 | [diff] [blame] | 127 | int got_pkts = 0; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 128 | aom_codec_iter_t iter = NULL; |
| 129 | const aom_codec_cx_pkt_t *pkt = NULL; |
| 130 | const aom_codec_err_t res = |
| 131 | aom_codec_encode(codec, img, frame_index, 1, 0, AOM_DL_GOOD_QUALITY); |
| 132 | if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame"); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 133 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 134 | while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) { |
Dmitry Kovalev | a8e674d | 2014-08-15 17:15:17 -0700 | [diff] [blame] | 135 | got_pkts = 1; |
| 136 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 137 | if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) { |
| 138 | const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0; |
| 139 | if (!aom_video_writer_write_frame(writer, pkt->data.frame.buf, |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 140 | pkt->data.frame.sz, |
| 141 | pkt->data.frame.pts)) { |
| 142 | die_codec(codec, "Failed to write compressed frame"); |
| 143 | } |
| 144 | |
| 145 | printf(keyframe ? "K" : "."); |
| 146 | fflush(stdout); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 147 | } |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 148 | } |
Dmitry Kovalev | a8e674d | 2014-08-15 17:15:17 -0700 | [diff] [blame] | 149 | |
| 150 | return got_pkts; |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | int main(int argc, char **argv) { |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 154 | FILE *infile = NULL; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 155 | aom_codec_ctx_t codec; |
| 156 | aom_codec_enc_cfg_t cfg; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 157 | int frame_count = 0; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 158 | aom_image_t raw; |
| 159 | aom_codec_err_t res; |
| 160 | AvxVideoInfo info; |
| 161 | AvxVideoWriter *writer = NULL; |
| 162 | const AvxInterface *encoder = NULL; |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 163 | const int fps = 2; // TODO(dkovalev) add command line argument |
Alex Converse | b528d49 | 2014-03-10 16:08:58 -0700 | [diff] [blame] | 164 | const double bits_per_pixel_per_frame = 0.067; |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 165 | |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 166 | exec_name = argv[0]; |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 167 | if (argc != 6) die("Invalid number of arguments"); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 168 | |
Yaowu Xu | 7083560 | 2014-05-13 09:32:18 -0700 | [diff] [blame] | 169 | memset(&info, 0, sizeof(info)); |
| 170 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 171 | encoder = get_aom_encoder_by_name(argv[1]); |
Jim Bankoski | 812506b | 2014-08-19 14:56:09 -0700 | [diff] [blame] | 172 | if (encoder == NULL) { |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 173 | die("Unsupported codec."); |
Jim Bankoski | 812506b | 2014-08-19 14:56:09 -0700 | [diff] [blame] | 174 | } |
| 175 | assert(encoder != NULL); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 176 | info.codec_fourcc = encoder->fourcc; |
Alex Converse | 61ecd7f | 2014-03-10 16:13:49 -0700 | [diff] [blame] | 177 | info.frame_width = strtol(argv[2], NULL, 0); |
| 178 | info.frame_height = strtol(argv[3], NULL, 0); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 179 | info.time_base.numerator = 1; |
| 180 | info.time_base.denominator = fps; |
| 181 | |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 182 | if (info.frame_width <= 0 || info.frame_height <= 0 || |
| 183 | (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) { |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 184 | die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); |
| 185 | } |
| 186 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 187 | if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, info.frame_width, |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 188 | info.frame_height, 1)) { |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 189 | die("Failed to allocate image."); |
| 190 | } |
| 191 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 192 | printf("Using %s\n", aom_codec_iface_name(encoder->codec_interface())); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 193 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 194 | res = aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0); |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 195 | if (res) die_codec(&codec, "Failed to get default codec config."); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 196 | |
| 197 | cfg.g_w = info.frame_width; |
| 198 | cfg.g_h = info.frame_height; |
| 199 | cfg.g_timebase.num = info.time_base.numerator; |
| 200 | cfg.g_timebase.den = info.time_base.denominator; |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 201 | cfg.rc_target_bitrate = |
| 202 | (unsigned int)(bits_per_pixel_per_frame * cfg.g_w * cfg.g_h * fps / 1000); |
Alex Converse | 61ecd7f | 2014-03-10 16:13:49 -0700 | [diff] [blame] | 203 | cfg.g_lag_in_frames = 0; |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 204 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 205 | writer = aom_video_writer_open(argv[5], kContainerIVF, &info); |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 206 | if (!writer) die("Failed to open %s for writing.", argv[5]); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 207 | |
Alex Converse | 61ecd7f | 2014-03-10 16:13:49 -0700 | [diff] [blame] | 208 | if (!(infile = fopen(argv[4], "rb"))) |
| 209 | die("Failed to open %s for reading.", argv[4]); |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 210 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 211 | if (aom_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0)) |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 212 | die_codec(&codec, "Failed to initialize encoder"); |
| 213 | |
Dmitry Kovalev | a8e674d | 2014-08-15 17:15:17 -0700 | [diff] [blame] | 214 | // Encode frames. |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 215 | while (aom_img_read(&raw, infile)) { |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 216 | ++frame_count; |
| 217 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 218 | if (frame_count == 22 && encoder->fourcc == AV1_FOURCC) { |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 219 | set_roi_map(&cfg, &codec); |
| 220 | } else if (frame_count == 33) { |
| 221 | set_active_map(&cfg, &codec); |
| 222 | } else if (frame_count == 44) { |
| 223 | unset_active_map(&cfg, &codec); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 224 | } |
| 225 | |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 226 | encode_frame(&codec, &raw, frame_count, writer); |
| 227 | } |
Dmitry Kovalev | a8e674d | 2014-08-15 17:15:17 -0700 | [diff] [blame] | 228 | |
| 229 | // Flush encoder. |
clang-format | 397d964 | 2016-08-08 18:51:16 -0700 | [diff] [blame] | 230 | while (encode_frame(&codec, NULL, -1, writer)) { |
| 231 | } |
Dmitry Kovalev | a8e674d | 2014-08-15 17:15:17 -0700 | [diff] [blame] | 232 | |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 233 | printf("\n"); |
| 234 | fclose(infile); |
| 235 | printf("Processed %d frames.\n", frame_count); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 236 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 237 | aom_img_free(&raw); |
| 238 | if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec."); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 239 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame^] | 240 | aom_video_writer_close(writer); |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 241 | |
Dmitry Kovalev | 8837b02 | 2014-02-13 14:18:05 -0800 | [diff] [blame] | 242 | return EXIT_SUCCESS; |
Dmitry Kovalev | 50fa585 | 2014-01-07 15:15:25 -0800 | [diff] [blame] | 243 | } |