// dump accumulated statistics and reset accumulated values const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { int number_of_frames, number_of_keyframes, encode_frame_count; int i; uint32_t bytes_total = 0; SvcInternal *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || si == NULL) return NULL; svc_log_reset(svc_ctx); encode_frame_count = si->encode_frame_count; if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); svc_log(svc_ctx, SVC_LOG_INFO, "\n"); number_of_keyframes = encode_frame_count / si->kf_dist + 1; for (i = 0; i < si->layers; ++i) { number_of_frames = encode_frame_count; if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && (i == 1 || i == 3)) { number_of_frames -= number_of_keyframes; } svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d PSNR=[%2.3f], Bytes=[%u]\n", i, (double)si->psnr_in_layer[i] / number_of_frames, si->bytes_in_layer[i]); bytes_total += si->bytes_in_layer[i]; si->psnr_in_layer[i] = 0; si->bytes_in_layer[i] = 0; } // only display statistics once si->encode_frame_count = 0; svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); return vpx_svc_get_message(svc_ctx); }
// dump accumulated statistics and reset accumulated values const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { int number_of_frames; int i, j; uint32_t bytes_total = 0; double scale[COMPONENTS]; double psnr[COMPONENTS]; double mse[COMPONENTS]; double y_scale; SvcInternal *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || si == NULL) return NULL; svc_log_reset(svc_ctx); number_of_frames = si->psnr_pkt_received; if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx); svc_log(svc_ctx, SVC_LOG_INFO, "\n"); for (i = 0; i < svc_ctx->spatial_layers; ++i) { svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", i, (double)si->psnr_sum[i][0] / number_of_frames, (double)si->psnr_sum[i][1] / number_of_frames, (double)si->psnr_sum[i][2] / number_of_frames, (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); // the following psnr calculation is deduced from ffmpeg.c#print_report y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; scale[1] = y_scale; scale[2] = scale[3] = y_scale / 4; // U or V scale[0] = y_scale * 1.5; // total for (j = 0; j < COMPONENTS; j++) { psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]); mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j]; } svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0], psnr[1], psnr[2], psnr[3]); svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], mse[1], mse[2], mse[3]); bytes_total += si->bytes_sum[i]; // clear sums for next time si->bytes_sum[i] = 0; for (j = 0; j < COMPONENTS; ++j) { si->psnr_sum[i][j] = 0; si->sse_sum[i][j] = 0; } } // only display statistics once si->psnr_pkt_received = 0; svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); return vpx_svc_get_message(svc_ctx); }
int main(int argc, const char **argv) { AppInput app_input = {0}; FILE *outfile; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t enc_cfg; SvcContext svc_ctx; uint32_t i; uint32_t frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; int pts = 0; /* PTS starts at 0 */ int frame_duration = 1; /* 1 timebase tick per frame */ vpx_codec_cx_pkt_t packet = {0}; packet.kind = VPX_CODEC_CX_FRAME_PKT; memset(&svc_ctx, 0, sizeof(svc_ctx)); svc_ctx.log_print = 1; exec_name = argv[0]; parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); // Allocate image buffer if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); if (!(app_input.input_ctx.file = fopen(app_input.input_ctx.filename, "rb"))) die("Failed to open %s for reading\n", app_input.input_ctx.filename); if (!(outfile = fopen(app_input.output_filename, "wb"))) die("Failed to open %s for writing\n", app_input.output_filename); // Initialize codec if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) != VPX_CODEC_OK) die("Failed to initialize encoder\n"); ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, 0); // skip initial frames for (i = 0; i < app_input.frames_to_skip; ++i) { read_yuv_frame(&app_input.input_ctx, &raw); } // Encode frames while (frame_cnt < app_input.frames_to_code) { if (read_yuv_frame(&app_input.input_ctx, &raw)) break; res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration, VPX_DL_REALTIME); printf("%s", vpx_svc_get_message(&svc_ctx)); if (res != VPX_CODEC_OK) { die_codec(&codec, "Failed to encode frame"); } if (vpx_svc_get_frame_size(&svc_ctx) > 0) { packet.data.frame.pts = pts; packet.data.frame.sz = vpx_svc_get_frame_size(&svc_ctx); ivf_write_frame_header(outfile, &packet); (void)fwrite(vpx_svc_get_buffer(&svc_ctx), 1, vpx_svc_get_frame_size(&svc_ctx), outfile); } ++frame_cnt; pts += frame_duration; } printf("Processed %d frames\n", frame_cnt); fclose(app_input.input_ctx.file); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); // rewrite the output file headers with the actual frame count, and // resolution of the highest layer if (!fseek(outfile, 0, SEEK_SET)) { // get resolution of highest layer if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1, &enc_cfg.g_w, &enc_cfg.g_h)) { die("Failed to get output resolution"); } ivf_write_file_header(outfile, &enc_cfg, VP9_FOURCC, frame_cnt); } fclose(outfile); vpx_img_free(&raw); // display average size, psnr printf("%s", vpx_svc_dump_statistics(&svc_ctx)); vpx_svc_release(&svc_ctx); return EXIT_SUCCESS; }
int main(int argc, const char **argv) { AppInput app_input = {0}; VpxVideoWriter *writer = NULL; VpxVideoInfo info = {0}; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t enc_cfg; SvcContext svc_ctx; uint32_t i; uint32_t frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; int pts = 0; /* PTS starts at 0 */ int frame_duration = 1; /* 1 timebase tick per frame */ FILE *infile = NULL; memset(&svc_ctx, 0, sizeof(svc_ctx)); svc_ctx.log_print = 1; exec_name = argv[0]; parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); // Allocate image buffer if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); if (!(infile = fopen(app_input.input_filename, "rb"))) die("Failed to open %s for reading\n", app_input.input_filename); // Initialize codec if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) != VPX_CODEC_OK) die("Failed to initialize encoder\n"); info.codec_fourcc = VP9_FOURCC; info.time_base.numerator = enc_cfg.g_timebase.num; info.time_base.denominator = enc_cfg.g_timebase.den; if (vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1, (unsigned int *)&info.frame_width, (unsigned int *)&info.frame_height) != VPX_CODEC_OK) { die("Failed to get output resolution"); } writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF, &info); if (!writer) die("Failed to open %s for writing\n", app_input.output_filename); // skip initial frames for (i = 0; i < app_input.frames_to_skip; ++i) vpx_img_read(&raw, infile); // Encode frames while (frame_cnt < app_input.frames_to_code) { if (!vpx_img_read(&raw, infile)) break; res = vpx_svc_encode(&svc_ctx, &codec, &raw, pts, frame_duration, VPX_DL_REALTIME); printf("%s", vpx_svc_get_message(&svc_ctx)); if (res != VPX_CODEC_OK) { die_codec(&codec, "Failed to encode frame"); } if (vpx_svc_get_frame_size(&svc_ctx) > 0) { vpx_video_writer_write_frame(writer, vpx_svc_get_buffer(&svc_ctx), vpx_svc_get_frame_size(&svc_ctx), pts); } ++frame_cnt; pts += frame_duration; } printf("Processed %d frames\n", frame_cnt); fclose(infile); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); vpx_video_writer_close(writer); vpx_img_free(&raw); // display average size, psnr printf("%s", vpx_svc_dump_statistics(&svc_ctx)); vpx_svc_release(&svc_ctx); return EXIT_SUCCESS; }
int main(int argc, const char **argv) { AppInput app_input = {0}; VpxVideoWriter *writer = NULL; VpxVideoInfo info = {0}; vpx_codec_ctx_t codec; vpx_codec_enc_cfg_t enc_cfg; SvcContext svc_ctx; uint32_t i; uint32_t frame_cnt = 0; vpx_image_t raw; vpx_codec_err_t res; int pts = 0; /* PTS starts at 0 */ int frame_duration = 1; /* 1 timebase tick per frame */ FILE *infile = NULL; int end_of_stream = 0; int frames_received = 0; memset(&svc_ctx, 0, sizeof(svc_ctx)); svc_ctx.log_print = 1; exec_name = argv[0]; parse_command_line(argc, argv, &app_input, &svc_ctx, &enc_cfg); // Allocate image buffer if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, enc_cfg.g_w, enc_cfg.g_h, 32)) die("Failed to allocate image %dx%d\n", enc_cfg.g_w, enc_cfg.g_h); if (!(infile = fopen(app_input.input_filename, "rb"))) die("Failed to open %s for reading\n", app_input.input_filename); // Initialize codec if (vpx_svc_init(&svc_ctx, &codec, vpx_codec_vp9_cx(), &enc_cfg) != VPX_CODEC_OK) die("Failed to initialize encoder\n"); info.codec_fourcc = VP9_FOURCC; info.time_base.numerator = enc_cfg.g_timebase.num; info.time_base.denominator = enc_cfg.g_timebase.den; if (vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1, (unsigned int *)&info.frame_width, (unsigned int *)&info.frame_height) != VPX_CODEC_OK) { die("Failed to get output resolution"); } if (!(app_input.passes == 2 && app_input.pass == 1)) { // We don't save the bitstream for the 1st pass on two pass rate control writer = vpx_video_writer_open(app_input.output_filename, kContainerIVF, &info); if (!writer) die("Failed to open %s for writing\n", app_input.output_filename); } // skip initial frames for (i = 0; i < app_input.frames_to_skip; ++i) vpx_img_read(&raw, infile); // Encode frames while (!end_of_stream) { vpx_codec_iter_t iter = NULL; const vpx_codec_cx_pkt_t *cx_pkt; if (frame_cnt >= app_input.frames_to_code || !vpx_img_read(&raw, infile)) { // We need one extra vpx_svc_encode call at end of stream to flush // encoder and get remaining data end_of_stream = 1; } res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw), pts, frame_duration, VPX_DL_GOOD_QUALITY); printf("%s", vpx_svc_get_message(&svc_ctx)); if (res != VPX_CODEC_OK) { die_codec(&codec, "Failed to encode frame"); } while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) { switch (cx_pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: { if (cx_pkt->data.frame.sz > 0) vpx_video_writer_write_frame(writer, cx_pkt->data.frame.buf, cx_pkt->data.frame.sz, cx_pkt->data.frame.pts); printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received, !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY), (int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts); ++frames_received; break; } case VPX_CODEC_STATS_PKT: { stats_write(&app_input.rc_stats, cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz); break; } default: { break; } } } if (!end_of_stream) { ++frame_cnt; pts += frame_duration; } } printf("Processed %d frames\n", frame_cnt); fclose(infile); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); if (app_input.passes == 2) stats_close(&app_input.rc_stats, 1); if (writer) { vpx_video_writer_close(writer); } vpx_img_free(&raw); // display average size, psnr printf("%s", vpx_svc_dump_statistics(&svc_ctx)); vpx_svc_release(&svc_ctx); return EXIT_SUCCESS; }