@@ -81,8 +81,6 @@ const smFlag = (mode: number): number => mode === SMOOTH_PRED || mode === SMOOTH
8181const ZERO_BITS = 0.6 ;
8282const coefBits = ( q : number ) : number => q === 0 ? ZERO_BITS : q === 1 ? 2.2 : q === 2 ? 3.4 : q < 15 ? 4.6 + Math . log2 ( q - 2 ) : 9 + 2 * Math . log2 ( q - 14 ) ;
8383
84- const SATD_BLOCK = new Int32Array ( 16 ) ;
85-
8684// whether the 8 most frequent of colors (their counts) cover most of n pixels (palettes are rarely better otherwise)
8785const mostlyFew = ( counts : number [ ] , n : number ) : boolean => {
8886 if ( counts . length <= 8 ) return true ;
@@ -323,9 +321,9 @@ class TileEncoder {
323321 result = { node : sp . node , cost : splitCost } ;
324322 }
325323 } else {
326- // 16x16: the whole block first (one without coefficients is rarely worth splitting)
324+ // 16x16: the whole block first (one without coefficients, or with few, is rarely worth splitting)
327325 const none = this . searchBlock ( bs , node . o ) ;
328- if ( none . b . skip && this . params . effort < 2 ) return { node : { bp : PARTITION_NONE , b : none . b , kids : [ ] } , cost : none . cost + this . lambda } ;
326+ if ( ( none . b . skip || none . bits < 30 ) && this . params . effort < 2 ) return { node : { bp : PARTITION_NONE , b : none . b , kids : [ ] } , cost : none . cost + this . lambda } ;
329327 const noneArea = this . saveArea ( bl ) ;
330328 this . restoreArea ( bl , saved ) ;
331329 const sp = split ( [ 0 , 1 , 2 , 3 ] ) ;
@@ -412,7 +410,7 @@ class TileEncoder {
412410 }
413411
414412 // the modes of a block (by rate and distortion), its reconstruction left in the frame
415- private searchBlock ( bs : number , edgeFlags : number ) : { b : Block , cost : number } {
413+ private searchBlock ( bs : number , edgeFlags : number ) : { b : Block , cost : number , bits : number } {
416414 const f = this . f , layout = f . layout ;
417415 const lw4 = bdim ( bs , 2 ) , lh4 = bdim ( bs , 3 ) ;
418416 const b : Block = {
@@ -495,9 +493,17 @@ class TileEncoder {
495493 if ( tdim ( b . tx , MAX ) <= TX_16X16 && this . params . effort && coded && ! this . lossless ) {
496494 // (the type's symbol: about 1 bit for DCT, 2.5 for the others)
497495 let keptTx = this . savePlane ( 0 , bs ) , bestTxCost = best + lambda ;
496+ // (a block of one transform: its prediction is the same for each type)
497+ const single = tdim ( b . tx , W ) >= Math . min ( bdim ( bs , 0 ) , this . f . bw - this . bx ) && tdim ( b . tx , H ) >= Math . min ( bdim ( bs , 1 ) , this . f . bh - this . by ) ;
498+ let prediction : Uint16Array | null = null ;
499+ if ( single ) {
500+ this . codeLuma ( bs , edgeFlags , b , true ) ;
501+ prediction = this . savePlane ( 0 , bs ) ;
502+ }
498503 for ( const txtp of [ ADST_ADST , ADST_DCT , DCT_ADST , IDTX ] ) {
499504 b . txtp = txtp ;
500- const d = this . codeLuma ( bs , edgeFlags , b ) ;
505+ if ( prediction ) this . restorePlane ( 0 , bs , prediction ) ;
506+ const d = this . codeLuma ( bs , edgeFlags , b , false , prediction !== null ) ;
501507 const cost = d + lambda * ( this . bits + 2.5 + ( b . yMode === DC_PRED ? 2 : 4.5 ) ) ;
502508 if ( cost < bestTxCost ) {
503509 bestTxCost = cost ;
@@ -593,7 +599,7 @@ class TileEncoder {
593599 }
594600 b . skip = coded ? 0 : 1 ;
595601 this . modeContexts ( bs , b ) ;
596- return { b, cost : dist + lambda * ( bits + 1 + 3 ) } ;
602+ return { b, cost : dist + lambda * ( bits + 1 + 3 ) , bits } ;
597603 }
598604
599605 // a palette for a block's luma, if it costs less than cost: its distortion and bits (without the mode's), the
@@ -769,22 +775,35 @@ class TileEncoder {
769775 private satd ( p : number , bs : number ) : number {
770776 const f = this . f , sx = p ? this . ssx : 0 , sy = p ? this . ssy : 0 , stride = f . strides [ p ] ;
771777 const w = bdim ( bs , 0 ) * 4 >> sx , h = bdim ( bs , 1 ) * 4 >> sy , x0 = this . bx * 4 >> sx , y0 = this . by * 4 >> sy ;
772- const pred = f . planes [ p ] , src = this . src [ p ] , d = SATD_BLOCK ;
778+ const pred = f . planes [ p ] , src = this . src [ p ] ;
773779 let sum = 0 ;
774780 for ( let by = 0 ; by < h ; by += 4 ) {
775781 for ( let bx = 0 ; bx < w ; bx += 4 ) {
776- for ( let y = 0 ; y < 4 ; y ++ ) {
777- const o = ( y0 + by + y ) * stride + x0 + bx ;
778- for ( let x = 0 ; x < 4 ; x ++ ) d [ y * 4 + x ] = src [ o + x ] - pred [ o + x ] ;
779- }
780- for ( let y = 0 ; y < 4 ; y ++ ) {
781- const a = d [ y * 4 ] + d [ y * 4 + 1 ] , b = d [ y * 4 ] - d [ y * 4 + 1 ] , c = d [ y * 4 + 2 ] + d [ y * 4 + 3 ] , e = d [ y * 4 + 2 ] - d [ y * 4 + 3 ] ;
782- d [ y * 4 ] = a + c ; d [ y * 4 + 1 ] = b + e ; d [ y * 4 + 2 ] = a - c ; d [ y * 4 + 3 ] = b - e ;
783- }
784- for ( let x = 0 ; x < 4 ; x ++ ) {
785- const a = d [ x ] + d [ 4 + x ] , b = d [ x ] - d [ 4 + x ] , c = d [ 8 + x ] + d [ 12 + x ] , e = d [ 8 + x ] - d [ 12 + x ] ;
786- sum += Math . abs ( a + c ) + Math . abs ( b + e ) + Math . abs ( a - c ) + Math . abs ( b - e ) ;
787- }
782+ // (rows, then columns; unrolled)
783+ let o = ( y0 + by ) * stride + x0 + bx ;
784+ const d00 = src [ o ] - pred [ o ] , d01 = src [ o + 1 ] - pred [ o + 1 ] , d02 = src [ o + 2 ] - pred [ o + 2 ] , d03 = src [ o + 3 ] - pred [ o + 3 ] ;
785+ o += stride ;
786+ const d10 = src [ o ] - pred [ o ] , d11 = src [ o + 1 ] - pred [ o + 1 ] , d12 = src [ o + 2 ] - pred [ o + 2 ] , d13 = src [ o + 3 ] - pred [ o + 3 ] ;
787+ o += stride ;
788+ const d20 = src [ o ] - pred [ o ] , d21 = src [ o + 1 ] - pred [ o + 1 ] , d22 = src [ o + 2 ] - pred [ o + 2 ] , d23 = src [ o + 3 ] - pred [ o + 3 ] ;
789+ o += stride ;
790+ const d30 = src [ o ] - pred [ o ] , d31 = src [ o + 1 ] - pred [ o + 1 ] , d32 = src [ o + 2 ] - pred [ o + 2 ] , d33 = src [ o + 3 ] - pred [ o + 3 ] ;
791+ const a0 = d00 + d01 , b0 = d00 - d01 , c0 = d02 + d03 , e0 = d02 - d03 ;
792+ const r00 = a0 + c0 , r01 = b0 + e0 , r02 = a0 - c0 , r03 = b0 - e0 ;
793+ const a1 = d10 + d11 , b1 = d10 - d11 , c1 = d12 + d13 , e1 = d12 - d13 ;
794+ const r10 = a1 + c1 , r11 = b1 + e1 , r12 = a1 - c1 , r13 = b1 - e1 ;
795+ const a2 = d20 + d21 , b2 = d20 - d21 , c2 = d22 + d23 , e2 = d22 - d23 ;
796+ const r20 = a2 + c2 , r21 = b2 + e2 , r22 = a2 - c2 , r23 = b2 - e2 ;
797+ const a3 = d30 + d31 , b3 = d30 - d31 , c3 = d32 + d33 , e3 = d32 - d33 ;
798+ const r30 = a3 + c3 , r31 = b3 + e3 , r32 = a3 - c3 , r33 = b3 - e3 ;
799+ let a = r00 + r10 , b = r00 - r10 , c = r20 + r30 , e = r20 - r30 ;
800+ sum += Math . abs ( a + c ) + Math . abs ( b + e ) + Math . abs ( a - c ) + Math . abs ( b - e ) ;
801+ a = r01 + r11 ; b = r01 - r11 ; c = r21 + r31 ; e = r21 - r31 ;
802+ sum += Math . abs ( a + c ) + Math . abs ( b + e ) + Math . abs ( a - c ) + Math . abs ( b - e ) ;
803+ a = r02 + r12 ; b = r02 - r12 ; c = r22 + r32 ; e = r22 - r32 ;
804+ sum += Math . abs ( a + c ) + Math . abs ( b + e ) + Math . abs ( a - c ) + Math . abs ( b - e ) ;
805+ a = r03 + r13 ; b = r03 - r13 ; c = r23 + r33 ; e = r23 - r33 ;
806+ sum += Math . abs ( a + c ) + Math . abs ( b + e ) + Math . abs ( a - c ) + Math . abs ( b - e ) ;
788807 }
789808 }
790809 // (the 4x4 Hadamard transform is 4 times as large as orthonormal)
@@ -834,7 +853,7 @@ class TileEncoder {
834853 }
835854
836855 // predicts and codes a block's luma (only predicts: predictOnly), returns the squared error
837- private codeLuma ( bs : number , edgeFlags : number , b : Block , predictOnly = false ) : number {
856+ private codeLuma ( bs : number , edgeFlags : number , b : Block , predictOnly = false , predicted = false ) : number {
838857 const f = this . f , seq = this . seq ;
839858 const bx = this . bx , by = this . by , bx4 = bx , by4 = by & 31 ;
840859 const bw4 = bdim ( bs , 0 ) , bh4 = bdim ( bs , 1 ) ;
@@ -865,7 +884,7 @@ class TileEncoder {
865884 const tx4 = bx + x ;
866885 const flags = ( ( ( y > initY || ! sbHasTr ) && x + tw >= subW4 ) ? 0 : EDGE_I444_TOP_HAS_RIGHT ) |
867886 ( ( x > initX || ( ! sbHasBl && y + th >= subH4 ) ) ? 0 : EDGE_I444_LEFT_HAS_BOTTOM ) ;
868- if ( ! palIdx ) {
887+ if ( ! palIdx && ! predicted ) {
869888 const mode = prepareEdges ( tx4 , tx4 > this . colStart , ty , ty > this . rowStart , this . colEnd , this . rowEnd , flags ,
870889 pic , d , stride , b . yMode , b . yAngle , tw , th , seq . intraEdgeFilter , f . bitdepth ) ;
871890 predict ( mode , pic , d , stride , tw * 4 , th * 4 , preparedAngle | intraFlags , 4 * f . bw - 4 * tx4 , 4 * f . bh - 4 * ty , f . bitdepthMax ) ;
0 commit comments