OLD | NEW |
| (Empty) |
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 | |
11 | |
12 // VP8 Set Active and ROI Maps | |
13 // =========================== | |
14 // | |
15 // This is an example demonstrating how to control the VP8 encoder's | |
16 // 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 | |
45 #include <stdio.h> | |
46 #include <stdlib.h> | |
47 #include <string.h> | |
48 | |
49 #define VPX_CODEC_DISABLE_COMPAT 1 | |
50 #include "vpx/vp8cx.h" | |
51 #include "vpx/vpx_encoder.h" | |
52 | |
53 #include "./tools_common.h" | |
54 #include "./video_writer.h" | |
55 | |
56 static const char *exec_name; | |
57 | |
58 void usage_exit() { | |
59 fprintf(stderr, "Usage: %s <width> <height> <infile> <outfile>\n", exec_name); | |
60 exit(EXIT_FAILURE); | |
61 } | |
62 | |
63 static void set_roi_map(const vpx_codec_enc_cfg_t *cfg, | |
64 vpx_codec_ctx_t *codec) { | |
65 unsigned int i; | |
66 vpx_roi_map_t roi = {0}; | |
67 | |
68 roi.rows = cfg->g_h / 16; | |
69 roi.cols = cfg->g_w / 16; | |
70 | |
71 roi.delta_q[0] = 0; | |
72 roi.delta_q[1] = -2; | |
73 roi.delta_q[2] = -4; | |
74 roi.delta_q[3] = -6; | |
75 | |
76 roi.delta_lf[0] = 0; | |
77 roi.delta_lf[1] = 1; | |
78 roi.delta_lf[2] = 2; | |
79 roi.delta_lf[3] = 3; | |
80 | |
81 roi.static_threshold[0] = 1500; | |
82 roi.static_threshold[1] = 1000; | |
83 roi.static_threshold[2] = 500; | |
84 roi.static_threshold[3] = 0; | |
85 | |
86 roi.roi_map = (uint8_t *)malloc(roi.rows * roi.cols); | |
87 for (i = 0; i < roi.rows * roi.cols; ++i) | |
88 roi.roi_map[i] = i % 4; | |
89 | |
90 if (vpx_codec_control(codec, VP8E_SET_ROI_MAP, &roi)) | |
91 die_codec(codec, "Failed to set ROI map"); | |
92 | |
93 free(roi.roi_map); | |
94 } | |
95 | |
96 static void set_active_map(const vpx_codec_enc_cfg_t *cfg, | |
97 vpx_codec_ctx_t *codec) { | |
98 unsigned int i; | |
99 vpx_active_map_t map = {0}; | |
100 | |
101 map.rows = cfg->g_h / 16; | |
102 map.cols = cfg->g_w / 16; | |
103 | |
104 map.active_map = (uint8_t *)malloc(map.rows * map.cols); | |
105 for (i = 0; i < map.rows * map.cols; ++i) | |
106 map.active_map[i] = i % 2; | |
107 | |
108 if (vpx_codec_control(codec, VP8E_SET_ACTIVEMAP, &map)) | |
109 die_codec(codec, "Failed to set active map"); | |
110 | |
111 free(map.active_map); | |
112 } | |
113 | |
114 static void unset_active_map(const vpx_codec_enc_cfg_t *cfg, | |
115 vpx_codec_ctx_t *codec) { | |
116 vpx_active_map_t map = {0}; | |
117 | |
118 map.rows = cfg->g_h / 16; | |
119 map.cols = cfg->g_w / 16; | |
120 map.active_map = NULL; | |
121 | |
122 if (vpx_codec_control(codec, VP8E_SET_ACTIVEMAP, &map)) | |
123 die_codec(codec, "Failed to set active map"); | |
124 } | |
125 | |
126 static void encode_frame(vpx_codec_ctx_t *codec, | |
127 vpx_image_t *img, | |
128 int frame_index, | |
129 VpxVideoWriter *writer) { | |
130 vpx_codec_iter_t iter = NULL; | |
131 const vpx_codec_cx_pkt_t *pkt = NULL; | |
132 const vpx_codec_err_t res = vpx_codec_encode(codec, img, frame_index, 1, 0, | |
133 VPX_DL_GOOD_QUALITY); | |
134 if (res != VPX_CODEC_OK) | |
135 die_codec(codec, "Failed to encode frame"); | |
136 | |
137 while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) { | |
138 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { | |
139 const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0; | |
140 if (!vpx_video_writer_write_frame(writer, | |
141 pkt->data.frame.buf, | |
142 pkt->data.frame.sz, | |
143 pkt->data.frame.pts)) { | |
144 die_codec(codec, "Failed to write compressed frame"); | |
145 } | |
146 | |
147 printf(keyframe ? "K" : "."); | |
148 fflush(stdout); | |
149 } | |
150 } | |
151 } | |
152 | |
153 int main(int argc, char **argv) { | |
154 FILE *infile = NULL; | |
155 vpx_codec_ctx_t codec = {0}; | |
156 vpx_codec_enc_cfg_t cfg = {0}; | |
157 int frame_count = 0; | |
158 vpx_image_t raw = {0}; | |
159 vpx_codec_err_t res; | |
160 VpxVideoInfo info = {0}; | |
161 VpxVideoWriter *writer = NULL; | |
162 const VpxInterface *encoder = NULL; | |
163 const int fps = 2; // TODO(dkovalev) add command line argument | |
164 const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument | |
165 | |
166 exec_name = argv[0]; | |
167 | |
168 if (argc != 5) | |
169 die("Invalid number of arguments"); | |
170 | |
171 encoder = get_vpx_encoder_by_name("vp8"); // only vp8 for now | |
172 if (!encoder) | |
173 die("Unsupported codec."); | |
174 | |
175 info.codec_fourcc = encoder->fourcc; | |
176 info.frame_width = strtol(argv[1], NULL, 0); | |
177 info.frame_height = strtol(argv[2], NULL, 0); | |
178 info.time_base.numerator = 1; | |
179 info.time_base.denominator = fps; | |
180 | |
181 if (info.frame_width <= 0 || | |
182 info.frame_height <= 0 || | |
183 (info.frame_width % 2) != 0 || | |
184 (info.frame_height % 2) != 0) { | |
185 die("Invalid frame size: %dx%d", info.frame_width, info.frame_height); | |
186 } | |
187 | |
188 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width, | |
189 info.frame_height, 1)) { | |
190 die("Failed to allocate image."); | |
191 } | |
192 | |
193 printf("Using %s\n", vpx_codec_iface_name(encoder->interface())); | |
194 | |
195 res = vpx_codec_enc_config_default(encoder->interface(), &cfg, 0); | |
196 if (res) | |
197 die_codec(&codec, "Failed to get default codec config."); | |
198 | |
199 cfg.g_w = info.frame_width; | |
200 cfg.g_h = info.frame_height; | |
201 cfg.g_timebase.num = info.time_base.numerator; | |
202 cfg.g_timebase.den = info.time_base.denominator; | |
203 cfg.rc_target_bitrate = bitrate; | |
204 | |
205 writer = vpx_video_writer_open(argv[4], kContainerIVF, &info); | |
206 if (!writer) | |
207 die("Failed to open %s for writing.", argv[4]); | |
208 | |
209 if (!(infile = fopen(argv[3], "rb"))) | |
210 die("Failed to open %s for reading.", argv[3]); | |
211 | |
212 if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0)) | |
213 die_codec(&codec, "Failed to initialize encoder"); | |
214 | |
215 while (vpx_img_read(&raw, infile)) { | |
216 ++frame_count; | |
217 | |
218 if (frame_count == 22) { | |
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); | |
224 } | |
225 | |
226 encode_frame(&codec, &raw, frame_count, writer); | |
227 } | |
228 encode_frame(&codec, NULL, -1, writer); | |
229 printf("\n"); | |
230 fclose(infile); | |
231 printf("Processed %d frames.\n", frame_count); | |
232 | |
233 vpx_img_free(&raw); | |
234 if (vpx_codec_destroy(&codec)) | |
235 die_codec(&codec, "Failed to destroy codec."); | |
236 | |
237 vpx_video_writer_close(writer); | |
238 | |
239 return EXIT_SUCCESS; | |
240 } | |
OLD | NEW |