From 9330bd71a10a216aa0098b2a7a6e17c40c247c27 Mon Sep 17 00:00:00 2001 From: angiebird Date: Sun, 10 Nov 2019 20:01:42 -0800 Subject: [PATCH] Add SimpleEncode::EncodeFrame() Change-Id: I08f074b7db2011f88769bd1d9d50cb376c238fe5 --- vp9/simple_encode.cc | 61 +++++++++++++++++++++++++++++++++++++++++--- vp9/simple_encode.h | 3 +++ vp9/vp9_cx_iface.c | 7 ++++- vp9/vp9_cx_iface.h | 3 +++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/vp9/simple_encode.cc b/vp9/simple_encode.cc index 6256d509b..a3adc0a67 100644 --- a/vp9/simple_encode.cc +++ b/vp9/simple_encode.cc @@ -46,6 +46,8 @@ static int img_read(vpx_image_t *img, FILE *file) { class SimpleEncode::impl { public: VP9_COMP *cpi; + vpx_img_fmt_t img_fmt; + vpx_image_t tmp_img; std::vector frame_stats; }; @@ -83,14 +85,14 @@ SimpleEncode::SimpleEncode(int frame_width, int frame_height, this->num_frames = num_frames; this->file = file; pimpl->cpi = NULL; + pimpl->img_fmt = VPX_IMG_FMT_I420; } void SimpleEncode::ComputeFirstPassStats() { - const vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420; vpx_rational_t frame_rate = make_vpx_rational(frame_rate_num, frame_rate_den); const VP9EncoderConfig oxcf = vp9_get_encoder_config( frame_width, frame_height, frame_rate, target_bitrate, VPX_RC_FIRST_PASS); - VP9_COMP *cpi = init_encoder(&oxcf, img_fmt); + VP9_COMP *cpi = init_encoder(&oxcf, pimpl->img_fmt); struct lookahead_ctx *lookahead = cpi->lookahead; int i; int use_highbitdepth = 0; @@ -98,7 +100,7 @@ void SimpleEncode::ComputeFirstPassStats() { use_highbitdepth = cpi->common.use_highbitdepth; #endif vpx_image_t img; - vpx_img_alloc(&img, img_fmt, frame_width, frame_height, 1); + vpx_img_alloc(&img, pimpl->img_fmt, frame_width, frame_height, 1); rewind(file); pimpl->frame_stats.clear(); for (i = 0; i < num_frames; ++i) { @@ -156,18 +158,69 @@ std::vector> SimpleEncode::ObserveFirstPassStats() { } void SimpleEncode::StartEncode() { + assert(pimpl->frame_stats.size() > 0); vpx_rational_t frame_rate = make_vpx_rational(frame_rate_num, frame_rate_den); VP9EncoderConfig oxcf = vp9_get_encoder_config( frame_width, frame_height, frame_rate, target_bitrate, VPX_RC_LAST_PASS); + vpx_fixed_buf_t stats; + stats.buf = pimpl->frame_stats.data(); + stats.sz = sizeof(pimpl->frame_stats[0]) * pimpl->frame_stats.size(); + + vp9_set_first_pass_stats(&oxcf, &stats); assert(pimpl->cpi == NULL); - pimpl->cpi = init_encoder(&oxcf, VPX_IMG_FMT_I420); + pimpl->cpi = init_encoder(&oxcf, pimpl->img_fmt); + vpx_img_alloc(&pimpl->tmp_img, pimpl->img_fmt, frame_width, frame_height, 1); rewind(file); } void SimpleEncode::EndEncode() { free_encoder(pimpl->cpi); pimpl->cpi = nullptr; + vpx_img_free(&pimpl->tmp_img); rewind(file); } +void SimpleEncode::EncodeFrame(char *cx_data, size_t *size, size_t max_size) { + VP9_COMP *cpi = pimpl->cpi; + struct lookahead_ctx *lookahead = cpi->lookahead; + int use_highbitdepth = 0; +#if CONFIG_VP9_HIGHBITDEPTH + use_highbitdepth = cpi->common.use_highbitdepth; +#endif + // The lookahead's size is set to oxcf->lag_in_frames. + // We want to fill lookahead to it's max capacity if possible so that the + // encoder can construct alt ref frame in time. + // In the other words, we hope vp9_get_compressed_data to encode a frame + // every time in the function + while (!vp9_lookahead_full(lookahead)) { + // TODO(angiebird): Check whether we can move this file read logics to + // lookahead + if (img_read(&pimpl->tmp_img, file)) { + int next_show_idx = vp9_lookahead_next_show_idx(lookahead); + int64_t ts_start = + timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts, next_show_idx); + int64_t ts_end = timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts, + next_show_idx + 1); + YV12_BUFFER_CONFIG sd; + image2yuvconfig(&pimpl->tmp_img, &sd); + vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0); + } else { + break; + } + } + int64_t time_stamp; + int64_t time_end; + int flush = 1; // Make vp9_get_compressed_data encode a frame + unsigned int frame_flags = 0; + vp9_get_compressed_data(cpi, &frame_flags, size, + reinterpret_cast(cx_data), &time_stamp, + &time_end, flush); + // vp9_get_compressed_data is expected to encode a frame every time, so the + // data size should be greater than zero. + assert(*size > 0); + if (*size >= max_size) { + assert(0); + } +} + SimpleEncode::~SimpleEncode() {} diff --git a/vp9/simple_encode.h b/vp9/simple_encode.h index ff676d58f..6308ff5ea 100644 --- a/vp9/simple_encode.h +++ b/vp9/simple_encode.h @@ -22,6 +22,9 @@ class SimpleEncode { // Free the encoder void EndEncode(); + // Encode a frame + void EncodeFrame(char *cx_data, size_t *size, size_t max_size); + private: class impl; int frame_width; diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 47c7be1df..a019b976c 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -566,7 +566,7 @@ static vpx_codec_err_t set_encoder_config( } oxcf->sharpness = extra_cfg->sharpness; - oxcf->two_pass_stats_in = cfg->rc_twopass_stats_in; + vp9_set_first_pass_stats(oxcf, &cfg->rc_twopass_stats_in); #if CONFIG_FP_MB_STATS oxcf->firstpass_mb_stats_in = cfg->rc_firstpass_mb_stats_in; @@ -1945,3 +1945,8 @@ FRAME_INFO vp9_get_frame_info(const VP9EncoderConfig *oxcf) { // TODO(angiebird): Figure out how to get subsampling_x/y here return frame_info; } + +void vp9_set_first_pass_stats(VP9EncoderConfig *oxcf, + const vpx_fixed_buf_t *stats) { + oxcf->two_pass_stats_in = *stats; +} diff --git a/vp9/vp9_cx_iface.h b/vp9/vp9_cx_iface.h index ed818b77d..59d864285 100644 --- a/vp9/vp9_cx_iface.h +++ b/vp9/vp9_cx_iface.h @@ -35,6 +35,9 @@ ticks_to_timebase_units(const vpx_rational64_t *timestamp_ratio, int64_t n) { return (n * timestamp_ratio->den + round) / timestamp_ratio->num; } +void vp9_set_first_pass_stats(VP9EncoderConfig *oxcf, + const vpx_fixed_buf_t *stats); + #ifdef __cplusplus } // extern "C" #endif -- 2.40.0