set_maps.c 7.37 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
John Koleszar's avatar
John Koleszar committed
3
 *
4
5
6
7
8
9
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
John Koleszar's avatar
John Koleszar committed
10
11
 */

Adrian Grange's avatar
Adrian Grange committed
12
// AOM Set Active and ROI Maps
13
14
// ===========================
//
Adrian Grange's avatar
Adrian Grange committed
15
// This is an example demonstrating how to control the AOM encoder's
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// ROI and Active maps.
//
// ROI (Reigon of Interest) maps are a way for the application to assign
// each macroblock in the image to a region, and then set quantizer and
// filtering parameters on that image.
//
// Active maps are a way for the application to specify on a
// macroblock-by-macroblock basis whether there is any activity in that
// macroblock.
//
//
// Configuration
// -------------
// An ROI map is set on frame 22. If the width of the image in macroblocks
// is evenly divisble by 4, then the output will appear to have distinct
// columns, where the quantizer, loopfilter, and static threshold differ
// from column to column.
//
// An active map is set on frame 33. If the width of the image in macroblocks
// is evenly divisble by 4, then the output will appear to have distinct
// columns, where one column will have motion and the next will not.
//
// The active map is cleared on frame 44.
//
// Observing The Effects
// ---------------------
// Use the `simple_decoder` example to decode this sample, and observe
// the change in the image at frames 22, 33, and 44.

45
#include <assert.h>
John Koleszar's avatar
John Koleszar committed
46
47
48
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
49

Adrian Grange's avatar
Adrian Grange committed
50
#include "aom/aomcx.h"
Adrian Grange's avatar
Adrian Grange committed
51
#include "aom/aom_encoder.h"
John Koleszar's avatar
John Koleszar committed
52

Tom Finegan's avatar
Tom Finegan committed
53
54
#include "../tools_common.h"
#include "../video_writer.h"
John Koleszar's avatar
John Koleszar committed
55

56
static const char *exec_name;
John Koleszar's avatar
John Koleszar committed
57

58
void usage_exit(void) {
59
60
  fprintf(stderr, "Usage: %s <codec> <width> <height> <infile> <outfile>\n",
          exec_name);
61
  exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
62
63
}

Adrian Grange's avatar
Adrian Grange committed
64
65
static void set_roi_map(const aom_codec_enc_cfg_t *cfg,
                        aom_codec_ctx_t *codec) {
66
  unsigned int i;
Adrian Grange's avatar
Adrian Grange committed
67
  aom_roi_map_t roi;
Yaowu Xu's avatar
Yaowu Xu committed
68
  memset(&roi, 0, sizeof(roi));
John Koleszar's avatar
John Koleszar committed
69

70
71
  roi.rows = (cfg->g_h + 15) / 16;
  roi.cols = (cfg->g_w + 15) / 16;
John Koleszar's avatar
John Koleszar committed
72

73
74
75
76
  roi.delta_q[0] = 0;
  roi.delta_q[1] = -2;
  roi.delta_q[2] = -4;
  roi.delta_q[3] = -6;
77

78
79
80
81
  roi.delta_lf[0] = 0;
  roi.delta_lf[1] = 1;
  roi.delta_lf[2] = 2;
  roi.delta_lf[3] = 3;
John Koleszar's avatar
John Koleszar committed
82

83
84
85
86
  roi.static_threshold[0] = 1500;
  roi.static_threshold[1] = 1000;
  roi.static_threshold[2] = 500;
  roi.static_threshold[3] = 0;
John Koleszar's avatar
John Koleszar committed
87

88
  roi.roi_map = (uint8_t *)malloc(roi.rows * roi.cols);
89
  for (i = 0; i < roi.rows * roi.cols; ++i) roi.roi_map[i] = i % 4;
John Koleszar's avatar
John Koleszar committed
90

Adrian Grange's avatar
Adrian Grange committed
91
  if (aom_codec_control(codec, AOME_SET_ROI_MAP, &roi))
92
93
94
    die_codec(codec, "Failed to set ROI map");

  free(roi.roi_map);
John Koleszar's avatar
John Koleszar committed
95
96
}

Adrian Grange's avatar
Adrian Grange committed
97
98
static void set_active_map(const aom_codec_enc_cfg_t *cfg,
                           aom_codec_ctx_t *codec) {
99
  unsigned int i;
Adrian Grange's avatar
Adrian Grange committed
100
  aom_active_map_t map = { 0, 0, 0 };
John Koleszar's avatar
John Koleszar committed
101

102
103
  map.rows = (cfg->g_h + 15) / 16;
  map.cols = (cfg->g_w + 15) / 16;
John Koleszar's avatar
John Koleszar committed
104

105
  map.active_map = (uint8_t *)malloc(map.rows * map.cols);
106
  for (i = 0; i < map.rows * map.cols; ++i) map.active_map[i] = i % 2;
John Koleszar's avatar
John Koleszar committed
107

Adrian Grange's avatar
Adrian Grange committed
108
  if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map))
109
    die_codec(codec, "Failed to set active map");
John Koleszar's avatar
John Koleszar committed
110

111
112
113
  free(map.active_map);
}

Adrian Grange's avatar
Adrian Grange committed
114
115
116
static void unset_active_map(const aom_codec_enc_cfg_t *cfg,
                             aom_codec_ctx_t *codec) {
  aom_active_map_t map = { 0, 0, 0 };
117

118
119
  map.rows = (cfg->g_h + 15) / 16;
  map.cols = (cfg->g_w + 15) / 16;
120
121
  map.active_map = NULL;

Adrian Grange's avatar
Adrian Grange committed
122
  if (aom_codec_control(codec, AOME_SET_ACTIVEMAP, &map))
123
124
125
    die_codec(codec, "Failed to set active map");
}

Adrian Grange's avatar
Adrian Grange committed
126
static int encode_frame(aom_codec_ctx_t *codec, aom_image_t *img,
127
                        int frame_index, VpxVideoWriter *writer) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
128
  int got_pkts = 0;
Adrian Grange's avatar
Adrian Grange committed
129
130
131
  aom_codec_iter_t iter = NULL;
  const aom_codec_cx_pkt_t *pkt = NULL;
  const aom_codec_err_t res =
Adrian Grange's avatar
Adrian Grange committed
132
133
      aom_codec_encode(codec, img, frame_index, 1, 0, AOM_DL_GOOD_QUALITY);
  if (res != AOM_CODEC_OK) die_codec(codec, "Failed to encode frame");
134

Adrian Grange's avatar
Adrian Grange committed
135
  while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
136
137
    got_pkts = 1;

Adrian Grange's avatar
Adrian Grange committed
138
139
    if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
      const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0;
Adrian Grange's avatar
Adrian Grange committed
140
      if (!aom_video_writer_write_frame(writer, pkt->data.frame.buf,
141
142
143
144
145
146
147
148
149
                                        pkt->data.frame.sz,
                                        pkt->data.frame.pts)) {
        die_codec(codec, "Failed to write compressed frame");
      }

      printf(keyframe ? "K" : ".");
      fflush(stdout);
    }
  }
Dmitry Kovalev's avatar
Dmitry Kovalev committed
150
151

  return got_pkts;
John Koleszar's avatar
John Koleszar committed
152
153
154
}

int main(int argc, char **argv) {
155
  FILE *infile = NULL;
Adrian Grange's avatar
Adrian Grange committed
156
157
  aom_codec_ctx_t codec;
  aom_codec_enc_cfg_t cfg;
158
  int frame_count = 0;
Adrian Grange's avatar
Adrian Grange committed
159
160
  aom_image_t raw;
  aom_codec_err_t res;
Yaowu Xu's avatar
Yaowu Xu committed
161
  VpxVideoInfo info;
162
163
  VpxVideoWriter *writer = NULL;
  const VpxInterface *encoder = NULL;
164
  const int fps = 2;  // TODO(dkovalev) add command line argument
165
  const double bits_per_pixel_per_frame = 0.067;
166
167

  exec_name = argv[0];
168
  if (argc != 6) die("Invalid number of arguments");
169

Yaowu Xu's avatar
Yaowu Xu committed
170
171
  memset(&info, 0, sizeof(info));

Adrian Grange's avatar
Adrian Grange committed
172
  encoder = get_aom_encoder_by_name(argv[1]);
173
  if (encoder == NULL) {
174
    die("Unsupported codec.");
175
176
  }
  assert(encoder != NULL);
177
  info.codec_fourcc = encoder->fourcc;
178
179
  info.frame_width = strtol(argv[2], NULL, 0);
  info.frame_height = strtol(argv[3], NULL, 0);
180
181
182
  info.time_base.numerator = 1;
  info.time_base.denominator = fps;

183
184
  if (info.frame_width <= 0 || info.frame_height <= 0 ||
      (info.frame_width % 2) != 0 || (info.frame_height % 2) != 0) {
185
186
187
    die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
  }

Adrian Grange's avatar
Adrian Grange committed
188
  if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, info.frame_width,
189
                     info.frame_height, 1)) {
190
191
192
    die("Failed to allocate image.");
  }

Adrian Grange's avatar
Adrian Grange committed
193
  printf("Using %s\n", aom_codec_iface_name(encoder->codec_interface()));
194

Adrian Grange's avatar
Adrian Grange committed
195
  res = aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
196
  if (res) die_codec(&codec, "Failed to get default codec config.");
197
198
199
200
201

  cfg.g_w = info.frame_width;
  cfg.g_h = info.frame_height;
  cfg.g_timebase.num = info.time_base.numerator;
  cfg.g_timebase.den = info.time_base.denominator;
202
203
  cfg.rc_target_bitrate =
      (unsigned int)(bits_per_pixel_per_frame * cfg.g_w * cfg.g_h * fps / 1000);
204
  cfg.g_lag_in_frames = 0;
205

Adrian Grange's avatar
Adrian Grange committed
206
  writer = aom_video_writer_open(argv[5], kContainerIVF, &info);
207
  if (!writer) die("Failed to open %s for writing.", argv[5]);
208

209
210
  if (!(infile = fopen(argv[4], "rb")))
    die("Failed to open %s for reading.", argv[4]);
211

Adrian Grange's avatar
Adrian Grange committed
212
  if (aom_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
213
214
    die_codec(&codec, "Failed to initialize encoder");

Dmitry Kovalev's avatar
Dmitry Kovalev committed
215
  // Encode frames.
Adrian Grange's avatar
Adrian Grange committed
216
  while (aom_img_read(&raw, infile)) {
217
218
    ++frame_count;

Adrian Grange's avatar
Adrian Grange committed
219
    if (frame_count == 22 && encoder->fourcc == AOM_FOURCC) {
220
221
222
223
224
      set_roi_map(&cfg, &codec);
    } else if (frame_count == 33) {
      set_active_map(&cfg, &codec);
    } else if (frame_count == 44) {
      unset_active_map(&cfg, &codec);
225
    }
John Koleszar's avatar
John Koleszar committed
226

227
228
    encode_frame(&codec, &raw, frame_count, writer);
  }
Dmitry Kovalev's avatar
Dmitry Kovalev committed
229
230

  // Flush encoder.
231
232
  while (encode_frame(&codec, NULL, -1, writer)) {
  }
Dmitry Kovalev's avatar
Dmitry Kovalev committed
233

234
235
236
237
  printf("\n");
  fclose(infile);
  printf("Processed %d frames.\n", frame_count);

Adrian Grange's avatar
Adrian Grange committed
238
239
  aom_img_free(&raw);
  if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
240

Adrian Grange's avatar
Adrian Grange committed
241
  aom_video_writer_close(writer);
242
243

  return EXIT_SUCCESS;
John Koleszar's avatar
John Koleszar committed
244
}