| 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 |