Ticket #8768: rescale.diff
| File rescale.diff, 12.4 KB (added by , 6 years ago) |
|---|
-
encoder/ratecontrol.c
From 14d4597dc855efbf008fb3db3ef3a300691075a7 Mon Sep 17 00:00:00 2001 From: Jason Garrett-Glaser <jason@x264.com> Date: Fri, 8 Jun 2012 18:19:59 -0700 Subject: [PATCH] Support changing resolutions between passes with macroblock-tree Implement a basic separable bilinear filter to rescale the quantizer offsets. Structure inspired by swscale, but floating-point instead of fixed-point. Not as optimized as it could be, but it's quite fast already. Example compression penalties on a 720p video game recording: First pass with 720p and second as 480p: ~-1.5% (vs. same res) First pass with 480p and second as 720p: ~-3% (vs. same res) --- encoder/ratecontrol.c | 191 ++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 167 insertions(+), 24 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index f9c8591..78b44f7 100644
a b struct x264_ratecontrol_t 136 136 double lmin[3]; /* min qscale by frame type */ 137 137 double lmax[3]; 138 138 double lstep; /* max change (multiply) in qscale per frame */ 139 uint16_t *qp_buffer[2]; /* Global buffers for converting MB-tree quantizer data. */ 140 int qpbuf_pos; /* In order to handle pyramid reordering, QP buffer acts as a stack. 139 struct 140 { 141 uint16_t *qp_buffer[2]; /* Global buffers for converting MB-tree quantizer data. */ 142 int qpbuf_pos; /* In order to handle pyramid reordering, QP buffer acts as a stack. 141 143 * This value is the current position (0 or 1). */ 144 int src_mb_count; 145 146 /* For rescaling */ 147 int rescale_enabled; 148 float *scale_buffer[2]; /* Intermediate buffers */ 149 int filtersize[2]; /* filter size (H/V) */ 150 float *coeffs[2]; 151 int *pos[2]; 152 int srcdim[2]; /* Source dimensions (W/H) */ 153 } mbtree; 142 154 143 155 /* MBRC stuff */ 144 156 float frame_size_estimated; /* Access to this variable must be atomic: double is … … void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_off 392 404 } 393 405 } 394 406 407 static int x264_macroblock_tree_rescale_init( x264_t *h, x264_ratecontrol_t *rc ) 408 { 409 /* Use fractional QP array dimensions to compensate for edge padding */ 410 float srcdim[2] = {rc->mbtree.srcdim[0] / 16.f, rc->mbtree.srcdim[1] / 16.f}; 411 float dstdim[2] = { h->param.i_width / 16.f, h->param.i_height / 16.f}; 412 int srcdimi[2] = {ceil(srcdim[0]), ceil(srcdim[1])}; 413 int dstdimi[2] = {ceil(dstdim[0]), ceil(dstdim[1])}; 414 if( PARAM_INTERLACED ) 415 { 416 srcdimi[1] = (srcdimi[1]+1)&~1; 417 dstdimi[1] = (dstdimi[1]+1)&~1; 418 } 419 420 rc->mbtree.src_mb_count = srcdimi[0] * srcdimi[1]; 421 422 CHECKED_MALLOC( rc->mbtree.qp_buffer[0], rc->mbtree.src_mb_count * sizeof(uint16_t) ); 423 if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read ) 424 CHECKED_MALLOC( rc->mbtree.qp_buffer[1], rc->mbtree.src_mb_count * sizeof(uint16_t) ); 425 rc->mbtree.qpbuf_pos = -1; 426 427 /* No rescaling to do */ 428 if( srcdimi[0] == dstdimi[0] && srcdimi[1] == dstdimi[1] ) 429 return 0; 430 431 rc->mbtree.rescale_enabled = 1; 432 433 /* Allocate intermediate scaling buffers */ 434 CHECKED_MALLOC( rc->mbtree.scale_buffer[0], srcdimi[0] * srcdimi[1] * sizeof(float) ); 435 CHECKED_MALLOC( rc->mbtree.scale_buffer[1], dstdimi[0] * srcdimi[1] * sizeof(float) ); 436 437 /* Allocate and calculate resize filter parameters and coefficients */ 438 for( int i = 0; i < 2; i++ ) 439 { 440 if( srcdim[i] > dstdim[i] ) // downscale 441 rc->mbtree.filtersize[i] = 1 + (2 * srcdimi[i] + dstdimi[i] - 1) / dstdimi[i]; 442 else // upscale 443 rc->mbtree.filtersize[i] = 3; 444 445 CHECKED_MALLOC( rc->mbtree.coeffs[i], rc->mbtree.filtersize[i] * dstdimi[i] * sizeof(float) ); 446 CHECKED_MALLOC( rc->mbtree.pos[i], dstdimi[i] * sizeof(int) ); 447 448 /* Initialize filter coefficients */ 449 float inc = srcdim[i] / dstdim[i]; 450 float dmul = inc > 1.f ? dstdim[i] / srcdim[i] : 1.f; 451 float dstinsrc = 0.5f * inc - 0.5f; 452 int filtersize = rc->mbtree.filtersize[i]; 453 for( int j = 0; j < dstdim[i]; j++ ) 454 { 455 int pos = dstinsrc - (filtersize - 2.f) * 0.5f; 456 float sum = 0.0; 457 rc->mbtree.pos[i][j] = pos; 458 for( int k = 0; k < filtersize; k++ ) 459 { 460 float d = fabs( pos + k - dstinsrc ) * dmul; 461 float coeff = X264_MAX( 1.f - d, 0 ); 462 rc->mbtree.coeffs[i][j * filtersize + k] = coeff; 463 sum += coeff; 464 } 465 sum = 1.0f / sum; 466 for( int k = 0; k < filtersize; k++ ) 467 rc->mbtree.coeffs[i][j * filtersize + k] *= sum; 468 dstinsrc += inc; 469 } 470 } 471 472 /* Write back actual qp array dimensions */ 473 rc->mbtree.srcdim[0] = srcdimi[0]; 474 rc->mbtree.srcdim[1] = srcdimi[1]; 475 return 0; 476 fail: 477 return -1; 478 } 479 480 static void x264_macroblock_tree_rescale_destroy( x264_ratecontrol_t *rc ) 481 { 482 for( int i = 0; i < 2; i++ ) 483 { 484 x264_free( rc->mbtree.scale_buffer[i] ); 485 x264_free( rc->mbtree.coeffs[i] ); 486 x264_free( rc->mbtree.pos[i] ); 487 } 488 } 489 490 static ALWAYS_INLINE float tapfilter( float *src, int pos, int max, int stride, float *coeff, int filtersize ) 491 { 492 float sum = 0.f; 493 for( int i = 0; i < filtersize; i++, pos++ ) 494 sum += src[x264_clip3( pos, 0, max-1 )*stride] * coeff[i]; 495 return sum; 496 } 497 498 static void x264_macroblock_tree_rescale( x264_t *h, x264_ratecontrol_t *rc, float *dst ) 499 { 500 float *input, *output; 501 int filtersize, stride, height; 502 503 /* H scale first */ 504 input = rc->mbtree.scale_buffer[0]; 505 output = rc->mbtree.scale_buffer[1]; 506 filtersize = rc->mbtree.filtersize[0]; 507 stride = rc->mbtree.srcdim[0]; 508 height = rc->mbtree.srcdim[1]; 509 for( int y = 0; y < height; y++, input += stride, output += h->mb.i_mb_width ) 510 { 511 float *coeff = rc->mbtree.coeffs[0]; 512 for( int x = 0; x < h->mb.i_mb_width; x++, coeff+=filtersize ) 513 output[x] = tapfilter( input, rc->mbtree.pos[0][x], stride, 1, coeff, filtersize ); 514 } 515 516 /* V scale next */ 517 input = rc->mbtree.scale_buffer[1]; 518 output = dst; 519 filtersize = rc->mbtree.filtersize[1]; 520 stride = h->mb.i_mb_width; 521 height = rc->mbtree.srcdim[1]; 522 for( int x = 0; x < h->mb.i_mb_width; x++, input++, output++ ) 523 { 524 float *coeff = rc->mbtree.coeffs[1]; 525 for( int y = 0; y < h->mb.i_mb_height; y++, coeff+=filtersize ) 526 output[y*stride] = tapfilter( input, rc->mbtree.pos[1][y], height, stride, coeff, filtersize ); 527 } 528 } 529 395 530 int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets ) 396 531 { 397 532 x264_ratecontrol_t *rc = h->rc; … … int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offs 400 535 if( rc->entry[frame->i_frame].kept_as_ref ) 401 536 { 402 537 uint8_t i_type; 403 if( rc-> qpbuf_pos < 0 )538 if( rc->mbtree.qpbuf_pos < 0 ) 404 539 { 405 540 do 406 541 { 407 rc-> qpbuf_pos++;542 rc->mbtree.qpbuf_pos++; 408 543 409 544 if( !fread( &i_type, 1, 1, rc->p_mbtree_stat_file_in ) ) 410 545 goto fail; 411 if( fread( rc-> qp_buffer[rc->qpbuf_pos], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_in ) != h->mb.i_mb_count )546 if( fread( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos], sizeof(uint16_t), rc->mbtree.src_mb_count, rc->p_mbtree_stat_file_in ) != rc->mbtree.src_mb_count ) 412 547 goto fail; 413 548 414 if( i_type != i_type_actual && rc-> qpbuf_pos == 1 )549 if( i_type != i_type_actual && rc->mbtree.qpbuf_pos == 1 ) 415 550 { 416 551 x264_log( h, X264_LOG_ERROR, "MB-tree frametype %d doesn't match actual frametype %d.\n", i_type, i_type_actual ); 417 552 return -1; … … int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offs 419 554 } while( i_type != i_type_actual ); 420 555 } 421 556 422 for( int i = 0; i < h->mb.i_mb_count; i++ ) 557 float *dst = rc->mbtree.rescale_enabled ? rc->mbtree.scale_buffer[0] : frame->f_qp_offset; 558 for( int i = 0; i < rc->mbtree.src_mb_count; i++ ) 423 559 { 424 frame->f_qp_offset[i] = ((float)(int16_t)endian_fix16( rc->qp_buffer[rc->qpbuf_pos][i] )) * (1/256.0); 425 if( h->frames.b_have_lowres ) 426 frame->i_inv_qscale_factor[i] = x264_exp2fix8(frame->f_qp_offset[i]); 560 int16_t qp_fix8 = endian_fix16( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos][i] ); 561 dst[i] = qp_fix8 * (1.f/256.f); 427 562 } 428 rc->qpbuf_pos--; 563 if( rc->mbtree.rescale_enabled ) 564 x264_macroblock_tree_rescale( h, rc, frame->f_qp_offset ); 565 if( h->frames.b_have_lowres ) 566 for( int i = 0; i < h->mb.i_mb_count; i++ ) 567 frame->i_inv_qscale_factor[i] = x264_exp2fix8( frame->f_qp_offset[i] ); 568 rc->mbtree.qpbuf_pos--; 429 569 } 430 570 else 431 571 x264_stack_align( x264_adaptive_quant_frame, h, frame, quant_offsets ); … … int x264_ratecontrol_new( x264_t *h ) 762 902 x264_log( h, X264_LOG_ERROR, "resolution specified in stats file not valid\n" ); 763 903 return -1; 764 904 } 765 else if( h->param.rc.b_mb_tree && (i != h->param.i_width || j != h->param.i_height))905 else if( h->param.rc.b_mb_tree ) 766 906 { 767 x264_log( h, X264_LOG_ERROR, "MB-tree doesn't support different resolution than 1st pass (%dx%d vs %dx%d)\n", 768 h->param.i_width, h->param.i_height, i, j ); 769 return -1; 907 rc->mbtree.srcdim[0] = i; 908 rc->mbtree.srcdim[1] = j; 770 909 } 771 910 res_factor = (float)h->param.i_width * h->param.i_height / (i*j); 772 911 /* Change in bits relative to resolution isn't quite linear on typical sources, … … parse_error: 1025 1164 1026 1165 if( h->param.rc.b_mb_tree && (h->param.rc.b_stat_read || h->param.rc.b_stat_write) ) 1027 1166 { 1028 CHECKED_MALLOC( rc->qp_buffer[0], h->mb.i_mb_count * sizeof(uint16_t) ); 1029 if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read ) 1030 CHECKED_MALLOC( rc->qp_buffer[1], h->mb.i_mb_count * sizeof(uint16_t) ); 1031 rc->qpbuf_pos = -1; 1167 if( !h->param.rc.b_stat_read ) 1168 { 1169 rc->mbtree.srcdim[0] = h->param.i_width; 1170 rc->mbtree.srcdim[1] = h->param.i_height; 1171 } 1172 if( x264_macroblock_tree_rescale_init( h, rc ) < 0 ) 1173 return -1; 1032 1174 } 1033 1175 1034 1176 for( int i = 0; i<h->param.i_threads; i++ ) … … void x264_ratecontrol_delete( x264_t *h ) 1216 1358 x264_free( rc->pred ); 1217 1359 x264_free( rc->pred_b_from_p ); 1218 1360 x264_free( rc->entry ); 1219 x264_free( rc->qp_buffer[0] ); 1220 x264_free( rc->qp_buffer[1] ); 1361 x264_free( rc->mbtree.qp_buffer[0] ); 1362 x264_free( rc->mbtree.qp_buffer[1] ); 1363 x264_macroblock_tree_rescale_destroy( rc ); 1221 1364 if( rc->zones ) 1222 1365 { 1223 1366 x264_free( rc->zones[0].param ); … … int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) 1708 1851 uint8_t i_type = h->sh.i_type; 1709 1852 /* Values are stored as big-endian FIX8.8 */ 1710 1853 for( int i = 0; i < h->mb.i_mb_count; i++ ) 1711 rc-> qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 );1854 rc->mbtree.qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 ); 1712 1855 if( fwrite( &i_type, 1, 1, rc->p_mbtree_stat_file_out ) < 1 ) 1713 1856 goto fail; 1714 if( fwrite( rc-> qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count )1857 if( fwrite( rc->mbtree.qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count ) 1715 1858 goto fail; 1716 1859 } 1717 1860 } … … void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) 2527 2670 COPY(short_term_cplxcount); 2528 2671 COPY(bframes); 2529 2672 COPY(prev_zone); 2530 COPY( qpbuf_pos);2673 COPY(mbtree.qpbuf_pos); 2531 2674 /* these vars can be updated by x264_ratecontrol_init_reconfigurable */ 2532 2675 COPY(bitrate); 2533 2676 COPY(buffer_size);
