OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 /* | 11 /* |
12 * This is an example demonstrating how to implement a multi-layer | 12 * This is an example demonstrating how to implement a multi-layer |
13 * VP9 encoding scheme based on spatial scalability for video applications | 13 * VP9 encoding scheme based on spatial scalability for video applications |
14 * that benefit from a scalable bitstream. | 14 * that benefit from a scalable bitstream. |
15 */ | 15 */ |
16 | 16 |
17 #include <stdarg.h> | 17 #include <stdarg.h> |
18 #include <stdlib.h> | 18 #include <stdlib.h> |
19 #include <string.h> | 19 #include <string.h> |
20 #include <time.h> | 20 #include <time.h> |
| 21 |
21 #include "./args.h" | 22 #include "./args.h" |
22 #include "./ivfenc.h" | |
23 #include "./tools_common.h" | 23 #include "./tools_common.h" |
| 24 #include "./video_writer.h" |
| 25 |
24 #include "vpx/svc_context.h" | 26 #include "vpx/svc_context.h" |
25 #include "vpx/vp8cx.h" | 27 #include "vpx/vp8cx.h" |
26 #include "vpx/vpx_encoder.h" | 28 #include "vpx/vpx_encoder.h" |
27 | 29 |
28 static const struct arg_enum_list encoding_mode_enum[] = { | 30 static const struct arg_enum_list encoding_mode_enum[] = { |
29 {"i", INTER_LAYER_PREDICTION_I}, | 31 {"i", INTER_LAYER_PREDICTION_I}, |
30 {"alt-ip", ALT_INTER_LAYER_PREDICTION_IP}, | 32 {"alt-ip", ALT_INTER_LAYER_PREDICTION_IP}, |
31 {"ip", INTER_LAYER_PREDICTION_IP}, | 33 {"ip", INTER_LAYER_PREDICTION_IP}, |
32 {"gf", USE_GOLDEN_FRAME}, | 34 {"gf", USE_GOLDEN_FRAME}, |
33 {NULL, 0} | 35 {NULL, 0} |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 static const uint32_t default_frames_to_code = 60 * 60; | 68 static const uint32_t default_frames_to_code = 60 * 60; |
67 static const uint32_t default_width = 1920; | 69 static const uint32_t default_width = 1920; |
68 static const uint32_t default_height = 1080; | 70 static const uint32_t default_height = 1080; |
69 static const uint32_t default_timebase_num = 1; | 71 static const uint32_t default_timebase_num = 1; |
70 static const uint32_t default_timebase_den = 60; | 72 static const uint32_t default_timebase_den = 60; |
71 static const uint32_t default_bitrate = 1000; | 73 static const uint32_t default_bitrate = 1000; |
72 static const uint32_t default_spatial_layers = 5; | 74 static const uint32_t default_spatial_layers = 5; |
73 static const uint32_t default_kf_dist = 100; | 75 static const uint32_t default_kf_dist = 100; |
74 | 76 |
75 typedef struct { | 77 typedef struct { |
76 char *output_filename; | 78 const char *input_filename; |
| 79 const char *output_filename; |
77 uint32_t frames_to_code; | 80 uint32_t frames_to_code; |
78 uint32_t frames_to_skip; | 81 uint32_t frames_to_skip; |
79 struct VpxInputContext input_ctx; | |
80 } AppInput; | 82 } AppInput; |
81 | 83 |
82 static const char *exec_name; | 84 static const char *exec_name; |
83 | 85 |
84 void usage_exit() { | 86 void usage_exit() { |
85 fprintf(stderr, "Usage: %s <options> input_filename output_filename\n", | 87 fprintf(stderr, "Usage: %s <options> input_filename output_filename\n", |
86 exec_name); | 88 exec_name); |
87 fprintf(stderr, "Options:\n"); | 89 fprintf(stderr, "Options:\n"); |
88 arg_show_usage(stderr, svc_args); | 90 arg_show_usage(stderr, svc_args); |
89 exit(EXIT_FAILURE); | 91 exit(EXIT_FAILURE); |
90 } | 92 } |
91 | 93 |
92 static void parse_command_line(int argc, const char **argv_, | 94 static void parse_command_line(int argc, const char **argv_, |
93 AppInput *app_input, SvcContext *svc_ctx, | 95 AppInput *app_input, SvcContext *svc_ctx, |
94 vpx_codec_enc_cfg_t *enc_cfg) { | 96 vpx_codec_enc_cfg_t *enc_cfg) { |
95 struct arg arg; | 97 struct arg arg = {0}; |
96 char **argv, **argi, **argj; | 98 char **argv = NULL; |
| 99 char **argi = NULL; |
| 100 char **argj = NULL; |
97 vpx_codec_err_t res; | 101 vpx_codec_err_t res; |
98 | 102 |
99 // initialize SvcContext with parameters that will be passed to vpx_svc_init | 103 // initialize SvcContext with parameters that will be passed to vpx_svc_init |
100 svc_ctx->log_level = SVC_LOG_DEBUG; | 104 svc_ctx->log_level = SVC_LOG_DEBUG; |
101 svc_ctx->spatial_layers = default_spatial_layers; | 105 svc_ctx->spatial_layers = default_spatial_layers; |
102 svc_ctx->encoding_mode = default_encoding_mode; | 106 svc_ctx->encoding_mode = default_encoding_mode; |
103 | 107 |
104 // start with default encoder configuration | 108 // start with default encoder configuration |
105 res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0); | 109 res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0); |
106 if (res) { | 110 if (res) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 } | 157 } |
154 | 158 |
155 // Check for unrecognized options | 159 // Check for unrecognized options |
156 for (argi = argv; *argi; ++argi) | 160 for (argi = argv; *argi; ++argi) |
157 if (argi[0][0] == '-' && strlen(argi[0]) > 1) | 161 if (argi[0][0] == '-' && strlen(argi[0]) > 1) |
158 die("Error: Unrecognized option %s\n", *argi); | 162 die("Error: Unrecognized option %s\n", *argi); |
159 | 163 |
160 if (argv[0] == NULL || argv[1] == 0) { | 164 if (argv[0] == NULL || argv[1] == 0) { |
161 usage_exit(); | 165 usage_exit(); |
162 } | 166 } |
163 app_input->input_ctx.filename = argv[0]; | 167 app_input->input_filename = argv[0]; |
164 app_input->output_filename = argv[1]; | 168 app_input->output_filename = argv[1]; |
165 free(argv); | 169 free(argv); |
166 | 170 |
167 if (enc_cfg->g_w < 16 || enc_cfg->g_w % 2 || enc_cfg->g_h < 16 || | 171 if (enc_cfg->g_w < 16 || enc_cfg->g_w % 2 || enc_cfg->g_h < 16 || |
168 enc_cfg->g_h % 2) | 172 enc_cfg->g_h % 2) |
169 die("Invalid resolution: %d x %d\n", enc_cfg->g_w, enc_cfg->g_h); | 173 die("Invalid resolution: %d x %d\n", enc_cfg->g_w, enc_cfg->g_h); |
170 | 174 |
171 printf( | 175 printf( |
172 "Codec %s\nframes: %d, skip: %d\n" | 176 "Codec %s\nframes: %d, skip: %d\n" |
173 "mode: %d, layers: %d\n" | 177 "mode: %d, layers: %d\n" |
174 "width %d, height: %d,\n" | 178 "width %d, height: %d,\n" |
175 "num: %d, den: %d, bitrate: %d,\n" | 179 "num: %d, den: %d, bitrate: %d,\n" |
176 "gop size: %d\n", | 180 "gop size: %d\n", |
177 vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code, | 181 vpx_codec_iface_name(vpx_codec_vp9_cx()), app_input->frames_to_code, |
178 app_input->frames_to_skip, svc_ctx->encoding_mode, | 182 app_input->frames_to_skip, svc_ctx->encoding_mode, |
179 svc_ctx->spatial_layers, enc_cfg->g_w, enc_cfg->g_h, | 183 svc_ctx->spatial_layers, enc_cfg->g_w, enc_cfg->g_h, |
180 enc_cfg->g_timebase.num, enc_cfg->g_timebase.den, | 184 enc_cfg->g_timebase.num, enc_cfg->g_timebase.den, |
181 enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist); | 185 enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist); |
182 } | 186 } |
183 | 187 |
184 int main(int argc, const char **argv) { | 188 int main(int argc, const char **argv) { |
185 AppInput app_input = {0}; | 189 AppInput app_input = {0}; |
186 FILE *outfile; | 190 VpxVideoWriter *writer = NULL; |
| 191 VpxVideoInfo info = {0}; |
187 vpx_codec_ctx_t codec; | 192 vpx_codec_ctx_t codec; |
188 vpx_codec_enc_cfg_t enc_cfg; | 193 vpx_codec_enc_cfg_t enc_cfg; |
189 SvcContext svc_ctx; | 194 SvcContext svc_ctx; |
190 uint32_t i; | 195 uint32_t i; |
191 uint32_t frame_cnt = 0; | 196 uint32_t frame_cnt = 0; |
192 vpx_image_t raw; | 197 vpx_image_t raw; |
193 vpx_codec_err_t res; | 198 vpx_codec_err_t res; |
194 int pts = 0; /* PTS starts at 0 */ | 199 int pts = 0; /* PTS starts at 0 */ |
195 int frame_duration = 1; /* 1 timebase tick per frame */ | 200 int frame_duration = 1; /* 1 timebase tick per frame */ |
196 vpx_codec_cx_pkt_t packet = {0}; | 201 FILE *infile = NULL; |
197 packet.kind = VPX_CODEC_CX_FRAME_PKT; | |
198 | 202 |
199 memset(&svc_ctx, 0, sizeof(svc_ctx)); | 203 memset(&svc_ctx, 0, sizeof(svc_ctx)); |
200 svc_ctx.log_print = 1; | 204 svc_ctx.log_print = 1; |
201 exec_name = argv[0]; | 205 exec_name = argv[0]; |
202 parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); | 206 parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); |
203 | 207 |
204 // Allocate image buffer | 208 // Allocate image buffer |
205 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) | 209 if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) |
206 die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); | 210 die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); |
207 | 211 |
208 if (!(app_input.input_ctx.file = fopen(app_input.input_ctx.filename, "rb"))) | 212 if (!(infile = fopen(app_input.input_filename, "rb"))) |
209 die("Failed to open %s for reading\n", app_input.input_ctx.filename); | 213 die("Failed to open %s for reading\n", app_input.input_filename); |
210 | |
211 if (!(outfile = fopen(app_input.output_filename, "wb"))) | |
212 die("Failed to open %s for writing\n", app_input.output_filename); | |
213 | 214 |
214 // Initialize codec | 215 // Initialize codec |
215 if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) != | 216 if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) != |
216 VPX_CODEC_OK) | 217 VPX_CODEC_OK) |
217 die("Failed to initialize encoder\n"); | 218 die("Failed to initialize encoder\n"); |
218 | 219 |
219 ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, 0); | 220 info.codec_fourcc = VP9_FOURCC; |
| 221 info.time_base.numerator = enc_cfg.g_timebase.num; |
| 222 info.time_base.denominator = enc_cfg.g_timebase.den; |
| 223 if (vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1, |
| 224 (unsigned int *)&info.frame_width, |
| 225 (unsigned int *)&info.frame_height) != |
| 226 VPX_CODEC_OK) { |
| 227 die("Failed to get output resolution"); |
| 228 } |
| 229 writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF, |
| 230 &info); |
| 231 if (!writer) |
| 232 die("Failed to open %s for writing\n", app_input.output_filename); |
220 | 233 |
221 // skip initial frames | 234 // skip initial frames |
222 for (i = 0; i < app_input.frames_to_skip; ++i) { | 235 for (i = 0; i < app_input.frames_to_skip; ++i) |
223 read_yuv_frame(&app_input.input_ctx, &raw); | 236 vpx_img_read(&raw, infile); |
224 } | |
225 | 237 |
226 // Encode frames | 238 // Encode frames |
227 while (frame_cnt < app_input.frames_to_code) { | 239 while (frame_cnt < app_input.frames_to_code) { |
228 if (read_yuv_frame(&app_input.input_ctx, &raw)) break; | 240 if (!vpx_img_read(&raw, infile)) |
| 241 break; |
229 | 242 |
230 res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration, | 243 res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration, |
231 VPX_DL_REALTIME); | 244 VPX_DL_REALTIME); |
232 printf("%s", vpx_svc_get_message(&svc_ctx)); | 245 printf("%s", vpx_svc_get_message(&svc_ctx)); |
233 if (res != VPX_CODEC_OK) { | 246 if (res != VPX_CODEC_OK) { |
234 die_codec(&codec, "Failed to encode frame"); | 247 die_codec(&codec, "Failed to encode frame"); |
235 } | 248 } |
236 if (vpx_svc_get_frame_size(&svc_ctx) > 0) { | 249 if (vpx_svc_get_frame_size(&svc_ctx) > 0) { |
237 packet.data.frame.pts = pts; | 250 vpx_video_writer_write_frame(writer, |
238 packet.data.frame.sz = vpx_svc_get_frame_size(&svc_ctx); | 251 vpx_svc_get_buffer(&svc_ctx), |
239 ivf_write_frame_header(outfile, &packet); | 252 vpx_svc_get_frame_size(&svc_ctx), |
240 (void)fwrite(vpx_svc_get_buffer(&svc_ctx), 1, | 253 pts); |
241 vpx_svc_get_frame_size(&svc_ctx), outfile); | |
242 } | 254 } |
243 ++frame_cnt; | 255 ++frame_cnt; |
244 pts += frame_duration; | 256 pts += frame_duration; |
245 } | 257 } |
246 | 258 |
247 printf("Processed %d frames\n", frame_cnt); | 259 printf("Processed %d frames\n", frame_cnt); |
248 | 260 |
249 fclose(app_input.input_ctx.file); | 261 fclose(infile); |
250 if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); | 262 if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); |
251 | 263 |
252 // rewrite the output file headers with the actual frame count, and | 264 vpx_video_writer_close(writer); |
253 // resolution of the highest layer | 265 |
254 if (!fseek(outfile, 0, SEEK_SET)) { | |
255 // get resolution of highest layer | |
256 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(&svc_ctx, | |
257 svc_ctx.spatial_layers - 1, | |
258 &enc_cfg.g_w, | |
259 &enc_cfg.g_h)) { | |
260 die("Failed to get output resolution"); | |
261 } | |
262 ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, frame_cnt); | |
263 } | |
264 fclose(outfile); | |
265 vpx_img_free(&raw); | 266 vpx_img_free(&raw); |
266 | 267 |
267 // display average size, psnr | 268 // display average size, psnr |
268 printf("%s", vpx_svc_dump_statistics(&svc_ctx)); | 269 printf("%s", vpx_svc_dump_statistics(&svc_ctx)); |
269 | 270 |
270 vpx_svc_release(&svc_ctx); | 271 vpx_svc_release(&svc_ctx); |
271 | 272 |
272 return EXIT_SUCCESS; | 273 return EXIT_SUCCESS; |
273 } | 274 } |
OLD | NEW |