From: Alex Converse Date: Thu, 15 Jan 2015 21:56:55 +0000 (-0800) Subject: Allow larger encoder configurations. X-Git-Tag: v1.4.0~199^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=797a2556eba26b2fbf89d339509ea9a8bb02dcc8;p=libvpx Allow larger encoder configurations. Allow changing colorspace in the encoder and increasing frame size. Change-Id: I8e7c3b891af29ce420a15beb4f6f9c250245b2bb --- diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h index 765c7d164..7b7dd3160 100644 --- a/test/encode_test_driver.h +++ b/test/encode_test_driver.h @@ -140,6 +140,12 @@ class Encoder { } #endif + void Config(const vpx_codec_enc_cfg_t *cfg) { + const vpx_codec_err_t res = vpx_codec_enc_config_set(&encoder_, cfg); + ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); + cfg_ = *cfg; + } + void set_deadline(unsigned long deadline) { deadline_ = deadline; } diff --git a/test/resize_test.cc b/test/resize_test.cc index 5c25dc11c..ef84156a3 100644 --- a/test/resize_test.cc +++ b/test/resize_test.cc @@ -261,9 +261,115 @@ TEST_P(ResizeInternalTest, TestInternalResizeWorks) { } } +vpx_img_fmt_t CspForFrameNumber(int frame) { + if (frame < 10) + return VPX_IMG_FMT_I420; + if (frame < 20) + return VPX_IMG_FMT_I444; + return VPX_IMG_FMT_I420; +} + +class ResizeCspTest : public ResizeTest { + protected: +#if WRITE_COMPRESSED_STREAM + ResizeCspTest() + : ResizeTest(), + frame0_psnr_(0.0), + outfile_(NULL), + out_frames_(0) {} +#else + ResizeCspTest() : ResizeTest(), frame0_psnr_(0.0) {} +#endif + + virtual ~ResizeCspTest() {} + + virtual void BeginPassHook(unsigned int /*pass*/) { +#if WRITE_COMPRESSED_STREAM + outfile_ = fopen("vp91-2-05-cspchape.ivf", "wb"); +#endif + } + + virtual void EndPassHook() { +#if WRITE_COMPRESSED_STREAM + if (outfile_) { + if (!fseek(outfile_, 0, SEEK_SET)) + write_ivf_file_header(&cfg_, out_frames_, outfile_); + fclose(outfile_); + outfile_ = NULL; + } +#endif + } + + virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video, + libvpx_test::Encoder *encoder) { + if (CspForFrameNumber(video->frame()) != VPX_IMG_FMT_I420 && + cfg_.g_profile != 1) { + cfg_.g_profile = 1; + encoder->Config(&cfg_); + } + if (CspForFrameNumber(video->frame()) == VPX_IMG_FMT_I420 && + cfg_.g_profile != 0) { + cfg_.g_profile = 0; + encoder->Config(&cfg_); + } + } + + virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) { + if (!frame0_psnr_) + frame0_psnr_ = pkt->data.psnr.psnr[0]; + EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0); + } + +#if WRITE_COMPRESSED_STREAM + virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { + ++out_frames_; + + // Write initial file header if first frame. + if (pkt->data.frame.pts == 0) + write_ivf_file_header(&cfg_, 0, outfile_); + + // Write frame header and data. + write_ivf_frame_header(pkt, outfile_); + (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); + } +#endif + + double frame0_psnr_; +#if WRITE_COMPRESSED_STREAM + FILE *outfile_; + unsigned int out_frames_; +#endif +}; + +class ResizingCspVideoSource : public ::libvpx_test::DummyVideoSource { + public: + ResizingCspVideoSource() { + SetSize(kInitialWidth, kInitialHeight); + limit_ = 30; + } + + virtual ~ResizingCspVideoSource() {} + + protected: + virtual void Next() { + ++frame_; + SetImageFormat(CspForFrameNumber(frame_)); + FillFrame(); + } +}; + +TEST_P(ResizeCspTest, TestResizeCspWorks) { + ResizingCspVideoSource video; + cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48; + cfg_.g_lag_in_frames = 0; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + VP8_INSTANTIATE_TEST_CASE(ResizeTest, ONE_PASS_TEST_MODES); VP9_INSTANTIATE_TEST_CASE(ResizeTest, ::testing::Values(::libvpx_test::kRealTime)); VP9_INSTANTIATE_TEST_CASE(ResizeInternalTest, ::testing::Values(::libvpx_test::kOnePassBest)); +VP9_INSTANTIATE_TEST_CASE(ResizeCspTest, + ::testing::Values(::libvpx_test::kRealTime)); } // namespace diff --git a/test/video_source.h b/test/video_source.h index b97e1550e..63294d14a 100644 --- a/test/video_source.h +++ b/test/video_source.h @@ -134,8 +134,13 @@ class VideoSource { class DummyVideoSource : public VideoSource { public: - DummyVideoSource() : img_(NULL), limit_(100), width_(0), height_(0) { - SetSize(80, 64); + DummyVideoSource() + : img_(NULL), + limit_(100), + width_(80), + height_(64), + format_(VPX_IMG_FMT_I420) { + ReallocImage(); } virtual ~DummyVideoSource() { vpx_img_free(img_); } @@ -174,23 +179,35 @@ class DummyVideoSource : public VideoSource { void SetSize(unsigned int width, unsigned int height) { if (width != width_ || height != height_) { - vpx_img_free(img_); - img_ = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, width, height, 32); - raw_sz_ = ((img_->w + 31) & ~31) * img_->h * 3 / 2; width_ = width; height_ = height; + ReallocImage(); + } + } + + void SetImageFormat(vpx_img_fmt_t format) { + if (format_ != format) { + format_ = format; + ReallocImage(); } } protected: virtual void FillFrame() { if (img_) memset(img_->img_data, 0, raw_sz_); } + void ReallocImage() { + vpx_img_free(img_); + img_ = vpx_img_alloc(NULL, format_, width_, height_, 32); + raw_sz_ = ((img_->w + 31) & ~31) * img_->h * img_->bps / 8; + } + vpx_image_t *img_; size_t raw_sz_; unsigned int limit_; unsigned int frame_; unsigned int width_; unsigned int height_; + vpx_img_fmt_t format_; }; diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index e93842726..7ae720a01 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -471,8 +471,9 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) { VP9_COMMON *cm = &cpi->common; const VP9EncoderConfig *oxcf = &cpi->oxcf; - cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height, - cm->subsampling_x, cm->subsampling_y, + if (!cpi->lookahead) + cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height, + cm->subsampling_x, cm->subsampling_y, #if CONFIG_VP9_HIGHBITDEPTH cm->use_highbitdepth, #endif @@ -1316,11 +1317,11 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) { cm->height = cpi->oxcf.height; if (cpi->initial_width) { - // Increasing the size of the frame beyond the first seen frame, or some - // otherwise signaled maximum size, is not supported. - // TODO(jkoleszar): exit gracefully. - assert(cm->width <= cpi->initial_width); - assert(cm->height <= cpi->initial_height); + if (cm->width > cpi->initial_width || cm->height > cpi->initial_height) { + vp9_free_context_buffers(cm); + vp9_alloc_context_buffers(cm, cm->width, cm->height); + cpi->initial_width = cpi->initial_height = 0; + } } update_frame_size(cpi); @@ -3439,7 +3440,11 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, unsigned int frame_flags, #endif vpx_usec_timer_start(&timer); - if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, frame_flags)) + if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, +#if CONFIG_VP9_HIGHBITDEPTH + use_highbitdepth, +#endif // CONFIG_VP9_HIGHBITDEPTH + frame_flags)) res = -1; vpx_usec_timer_mark(&timer); cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); diff --git a/vp9/encoder/vp9_lookahead.c b/vp9/encoder/vp9_lookahead.c index 708072ee2..b8e2ca88c 100644 --- a/vp9/encoder/vp9_lookahead.c +++ b/vp9/encoder/vp9_lookahead.c @@ -90,19 +90,40 @@ struct lookahead_ctx *vp9_lookahead_init(unsigned int width, #define USE_PARTIAL_COPY 0 int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, - int64_t ts_start, int64_t ts_end, unsigned int flags) { + int64_t ts_start, int64_t ts_end, +#if CONFIG_VP9_HIGHBITDEPTH + int use_highbitdepth, +#endif + unsigned int flags) { struct lookahead_entry *buf; #if USE_PARTIAL_COPY int row, col, active_end; int mb_rows = (src->y_height + 15) >> 4; int mb_cols = (src->y_width + 15) >> 4; #endif + int width = src->y_crop_width; + int height = src->y_crop_height; + int uv_width = src->uv_crop_width; + int uv_height = src->uv_crop_height; + int subsampling_x = src->subsampling_x; + int subsampling_y = src->subsampling_y; + int larger_dimensions, new_dimensions; if (ctx->sz + 1 + MAX_PRE_FRAMES > ctx->max_sz) return 1; ctx->sz++; buf = pop(ctx, &ctx->write_idx); + new_dimensions = width != buf->img.y_crop_width || + height != buf->img.y_crop_height || + uv_width != buf->img.uv_crop_width || + uv_height != buf->img.uv_crop_height; + larger_dimensions = width > buf->img.y_width || + height > buf->img.y_height || + uv_width > buf->img.uv_width || + uv_height > buf->img.uv_height; + assert(!larger_dimensions || new_dimensions); + #if USE_PARTIAL_COPY // TODO(jkoleszar): This is disabled for now, as // vp9_copy_and_extend_frame_with_rect is not subsampling/alpha aware. @@ -111,7 +132,7 @@ int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, // 1. Lookahead queue has has size of 1. // 2. Active map is provided. // 3. This is not a key frame, golden nor altref frame. - if (ctx->max_sz == 1 && active_map && !flags) { + if (!new_dimensions && ctx->max_sz == 1 && active_map && !flags) { for (row = 0; row < mb_rows; ++row) { col = 0; @@ -147,11 +168,32 @@ int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, active_map += mb_cols; } } else { +#endif + if (larger_dimensions) { + YV12_BUFFER_CONFIG new_img; + memset(&new_img, 0, sizeof(new_img)); + if (vp9_alloc_frame_buffer(&new_img, + width, height, subsampling_x, subsampling_y, +#if CONFIG_VP9_HIGHBITDEPTH + use_highbitdepth, +#endif + VP9_ENC_BORDER_IN_PIXELS, + 0)) + return 1; + vp9_free_frame_buffer(&buf->img); + buf->img = new_img; + } else if (new_dimensions) { + buf->img.y_crop_width = src->y_crop_width; + buf->img.y_crop_height = src->y_crop_height; + buf->img.uv_crop_width = src->uv_crop_width; + buf->img.uv_crop_height = src->uv_crop_height; + buf->img.subsampling_x = src->subsampling_x; + buf->img.subsampling_y = src->subsampling_y; + } + // Partial copy not implemented yet vp9_copy_and_extend_frame(src, &buf->img); +#if USE_PARTIAL_COPY } -#else - // Partial copy not implemented yet - vp9_copy_and_extend_frame(src, &buf->img); #endif buf->ts_start = ts_start; diff --git a/vp9/encoder/vp9_lookahead.h b/vp9/encoder/vp9_lookahead.h index a33d3002e..13820380f 100644 --- a/vp9/encoder/vp9_lookahead.h +++ b/vp9/encoder/vp9_lookahead.h @@ -79,7 +79,11 @@ void vp9_lookahead_destroy(struct lookahead_ctx *ctx); * \param[in] active_map Map that specifies which macroblock is active */ int vp9_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src, - int64_t ts_start, int64_t ts_end, unsigned int flags); + int64_t ts_start, int64_t ts_end, +#if CONFIG_VP9_HIGHBITDEPTH + int use_highbitdepth, +#endif + unsigned int flags); /**\brief Get the next source buffer to encode diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 589f0b1bf..4e62ffbb4 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -530,10 +530,9 @@ static vpx_codec_err_t encoder_set_config(vpx_codec_alg_priv_t *ctx, if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) { if (cfg->g_lag_in_frames > 1 || cfg->g_pass != VPX_RC_ONE_PASS) ERROR("Cannot change width or height after initialization"); - if ((ctx->cpi->initial_width && (int)cfg->g_w > ctx->cpi->initial_width) || + if (!valid_ref_frame_size(ctx->cfg.g_w, ctx->cfg.g_h, cfg->g_w, cfg->g_h) || + (ctx->cpi->initial_width && (int)cfg->g_w > ctx->cpi->initial_width) || (ctx->cpi->initial_height && (int)cfg->g_h > ctx->cpi->initial_height)) - ERROR("Cannot increase width or height larger than their initial values"); - if (!valid_ref_frame_size(ctx->cfg.g_w, ctx->cfg.g_h, cfg->g_w, cfg->g_h)) force_key = 1; }