1 /********************************************************************
3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2003 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
16 ********************************************************************/
19 #include "codec_internal.h"
20 #include "block_inline.h"
23 #define MAX_UP_REG_LOOPS 2
25 /* Gives the initial bytes per block estimate for each Q value */
26 double BpbTable
[Q_TABLE_SIZE
] = {
27 0.42, 0.45, 0.46, 0.49, 0.51, 0.53, 0.56, 0.58,
28 0.61, 0.64, 0.68, 0.71, 0.74, 0.77, 0.80, 0.84,
29 0.89, 0.92, 0.98, 1.01, 1.04, 1.13, 1.17, 1.23,
30 1.28, 1.34, 1.41, 1.45, 1.51, 1.59, 1.69, 1.80,
31 1.84, 1.94, 2.02, 2.15, 2.23, 2.34, 2.44, 2.50,
32 2.69, 2.80, 2.87, 3.04, 3.16, 3.29, 3.59, 3.66,
33 3.86, 3.94, 4.22, 4.50, 4.64, 4.70, 5.24, 5.34,
34 5.61, 5.87, 6.11, 6.41, 6.71, 6.99, 7.36, 7.69
37 double KfBpbTable
[Q_TABLE_SIZE
] = {
38 0.74, 0.81, 0.88, 0.94, 1.00, 1.06, 1.14, 1.19,
39 1.27, 1.34, 1.42, 1.49, 1.54, 1.59, 1.66, 1.73,
40 1.80, 1.87, 1.97, 2.01, 2.08, 2.21, 2.25, 2.36,
41 2.39, 2.50, 2.55, 2.65, 2.71, 2.82, 2.95, 3.01,
42 3.11, 3.19, 3.31, 3.42, 3.58, 3.66, 3.78, 3.89,
43 4.11, 4.26, 4.36, 4.39, 4.63, 4.76, 4.85, 5.04,
44 5.26, 5.29, 5.47, 5.64, 5.76, 6.05, 6.35, 6.67,
45 6.91, 7.17, 7.40, 7.56, 8.02, 8.45, 8.86, 9.38
48 double GetEstimatedBpb( CP_INSTANCE
*cpi
, ogg_uint32_t TargetQ
){
50 ogg_int32_t ThreshTableIndex
= Q_TABLE_SIZE
- 1;
53 /* Search for the Q table index that matches the given Q. */
54 for ( i
= 0; i
< Q_TABLE_SIZE
; i
++ ) {
55 if ( TargetQ
>= cpi
->pb
.QThreshTable
[i
] ) {
61 /* Adjust according to Q shift and type of frame */
62 if ( GetFrameType(&cpi
->pb
) == KEY_FRAME
) {
63 /* Get primary prediction */
64 BytesPerBlock
= KfBpbTable
[ThreshTableIndex
];
66 /* Get primary prediction */
67 BytesPerBlock
= BpbTable
[ThreshTableIndex
];
68 BytesPerBlock
= BytesPerBlock
* cpi
->BpbCorrectionFactor
;
74 static void UpRegulateMB( CP_INSTANCE
*cpi
, ogg_uint32_t RegulationQ
,
75 ogg_uint32_t SB
, ogg_uint32_t MB
, int NoCheck
) {
76 ogg_int32_t FragIndex
;
79 /* Variables used in calculating corresponding row,col and index in
82 ogg_uint32_t UVColumn
;
83 ogg_uint32_t UVFragOffset
;
85 /* There may be MB's lying out of frame which must be ignored. For
86 these MB's Top left block will have a negative Fragment Index. */
87 if ( QuadMapToMBTopLeft(cpi
->pb
.BlockMap
, SB
, MB
) >= 0 ) {
88 /* Up regulate the component blocks Y then UV. */
89 for ( B
=0; B
<4; B
++ ){
90 FragIndex
= QuadMapToIndex1( cpi
->pb
.BlockMap
, SB
, MB
, B
);
92 if ( ( !cpi
->pb
.display_fragments
[FragIndex
] ) &&
93 ( (NoCheck
) || (cpi
->FragmentLastQ
[FragIndex
] > RegulationQ
) ) ){
94 cpi
->pb
.display_fragments
[FragIndex
] = 1;
95 cpi
->extra_fragments
[FragIndex
] = 1;
96 cpi
->FragmentLastQ
[FragIndex
] = RegulationQ
;
101 /* Check the two UV blocks */
102 FragIndex
= QuadMapToMBTopLeft(cpi
->pb
.BlockMap
, SB
, MB
);
104 UVRow
= (FragIndex
/ (cpi
->pb
.HFragments
* 2));
105 UVColumn
= (FragIndex
% cpi
->pb
.HFragments
) / 2;
106 UVFragOffset
= (UVRow
* (cpi
->pb
.HFragments
/ 2)) + UVColumn
;
108 FragIndex
= cpi
->pb
.YPlaneFragments
+ UVFragOffset
;
109 if ( ( !cpi
->pb
.display_fragments
[FragIndex
] ) &&
110 ( (NoCheck
) || (cpi
->FragmentLastQ
[FragIndex
] > RegulationQ
) ) ) {
111 cpi
->pb
.display_fragments
[FragIndex
] = 1;
112 cpi
->extra_fragments
[FragIndex
] = 1;
113 cpi
->FragmentLastQ
[FragIndex
] = RegulationQ
;
117 FragIndex
+= cpi
->pb
.UVPlaneFragments
;
118 if ( ( !cpi
->pb
.display_fragments
[FragIndex
] ) &&
119 ( (NoCheck
) || (cpi
->FragmentLastQ
[FragIndex
] > RegulationQ
) ) ) {
120 cpi
->pb
.display_fragments
[FragIndex
] = 1;
121 cpi
->extra_fragments
[FragIndex
] = 1;
122 cpi
->FragmentLastQ
[FragIndex
] = RegulationQ
;
128 static void UpRegulateBlocks (CP_INSTANCE
*cpi
, ogg_uint32_t RegulationQ
,
129 ogg_int32_t RecoveryBlocks
,
130 ogg_uint32_t
* LastSB
, ogg_uint32_t
* LastMB
) {
132 ogg_uint32_t LoopTimesRound
= 0;
133 ogg_uint32_t MaxSB
= cpi
->pb
.YSBRows
*
134 cpi
->pb
.YSBCols
; /* Tot super blocks in image */
135 ogg_uint32_t SB
, MB
; /* Super-Block and macro block indices. */
137 /* First scan for blocks for which a residue update is outstanding. */
138 while ( (cpi
->MotionScore
< RecoveryBlocks
) &&
139 (LoopTimesRound
< MAX_UP_REG_LOOPS
) ) {
142 for ( SB
= (*LastSB
); SB
< MaxSB
; SB
++ ) {
143 /* Check its four Macro-Blocks */
144 for ( MB
=(*LastMB
); MB
<4; MB
++ ) {
145 /* Mark relevant blocks for update */
146 UpRegulateMB( cpi
, RegulationQ
, SB
, MB
, 0 );
148 /* Keep track of the last refresh MB. */
150 if ( (*LastMB
) == 4 )
153 /* Termination clause */
154 if (cpi
->MotionScore
>= RecoveryBlocks
) {
155 /* Make sure we don't stall at SB level */
162 /* Termination clause */
163 if (cpi
->MotionScore
>= RecoveryBlocks
)
167 /* Update super block start index */
176 void UpRegulateDataStream (CP_INSTANCE
*cpi
, ogg_uint32_t RegulationQ
,
177 ogg_int32_t RecoveryBlocks
) {
178 ogg_uint32_t LastPassMBPos
= 0;
179 ogg_uint32_t StdLastMBPos
= 0;
181 ogg_uint32_t MaxSB
= cpi
->pb
.YSBRows
*
182 cpi
->pb
.YSBCols
; /* Tot super blocks in image */
184 ogg_uint32_t SB
=0; /* Super-Block index */
185 ogg_uint32_t MB
; /* Macro-Block index */
187 /* Decduct the number of blocks in an MB / 2 from the recover block count.
188 This will compensate for the fact that once we start checking an MB
189 we test every block in that macro block */
190 if ( RecoveryBlocks
> 3 )
193 /* Up regulate blocks last coded at higher Q */
194 UpRegulateBlocks( cpi
, RegulationQ
, RecoveryBlocks
,
195 &cpi
->LastEndSB
, &StdLastMBPos
);
197 /* If we have still not used up the minimum number of blocks and are
198 at the minimum Q then run through a final pass of the data to
199 insure that each block gets a final refresh. */
200 if ( (RegulationQ
== VERY_BEST_Q
) &&
201 (cpi
->MotionScore
< RecoveryBlocks
) ) {
202 if ( cpi
->FinalPassLastPos
< MaxSB
) {
203 for ( SB
= cpi
->FinalPassLastPos
; SB
< MaxSB
; SB
++ ) {
204 /* Check its four Macro-Blocks */
205 for ( MB
=LastPassMBPos
; MB
<4; MB
++ ) {
206 /* Mark relevant blocks for update */
207 UpRegulateMB( cpi
, RegulationQ
, SB
, MB
, 1 );
209 /* Keep track of the last refresh MB. */
211 if ( LastPassMBPos
== 4 ) {
214 /* Increment SB index */
215 cpi
->FinalPassLastPos
+= 1;
218 /* Termination clause */
219 if (cpi
->MotionScore
>= RecoveryBlocks
)
223 /* Termination clause */
224 if (cpi
->MotionScore
>= RecoveryBlocks
)
232 void RegulateQ( CP_INSTANCE
*cpi
, ogg_int32_t UpdateScore
) {
233 double PredUnitScoreBytes
;
234 ogg_uint32_t QIndex
= Q_TABLE_SIZE
- 1;
237 if ( UpdateScore
> 0 ) {
238 double TargetUnitScoreBytes
= (double)cpi
->ThisFrameTargetBytes
/
240 double LastBitError
= 10000.0; /* Silly high number */
241 /* Search for the best Q for the target bitrate. */
242 for ( i
= 0; i
< Q_TABLE_SIZE
; i
++ ) {
243 PredUnitScoreBytes
= GetEstimatedBpb( cpi
, cpi
->pb
.QThreshTable
[i
] );
244 if ( PredUnitScoreBytes
> TargetUnitScoreBytes
) {
245 if ( (PredUnitScoreBytes
- TargetUnitScoreBytes
) <= LastBitError
) {
252 LastBitError
= TargetUnitScoreBytes
- PredUnitScoreBytes
;
257 /* QIndex should now indicate the optimal Q. */
258 cpi
->pb
.ThisFrameQualityValue
= cpi
->pb
.QThreshTable
[QIndex
];
260 /* Apply range restrictions for key frames. */
261 if ( GetFrameType(&cpi
->pb
) == KEY_FRAME
) {
262 if ( cpi
->pb
.ThisFrameQualityValue
> cpi
->pb
.QThreshTable
[20] )
263 cpi
->pb
.ThisFrameQualityValue
= cpi
->pb
.QThreshTable
[20];
264 else if ( cpi
->pb
.ThisFrameQualityValue
< cpi
->pb
.QThreshTable
[50] )
265 cpi
->pb
.ThisFrameQualityValue
= cpi
->pb
.QThreshTable
[50];
268 /* Limit the Q value to the maximum available value */
269 if (cpi
->pb
.ThisFrameQualityValue
>
270 cpi
->pb
.QThreshTable
[cpi
->Configuration
.ActiveMaxQ
]) {
271 cpi
->pb
.ThisFrameQualityValue
=
272 (ogg_uint32_t
)cpi
->pb
.QThreshTable
[cpi
->Configuration
.ActiveMaxQ
];
276 if ( GetFrameType(&cpi
->pb
) == KEY_FRAME
) {
277 cpi
->pb
.ThisFrameQualityValue
= cpi
->pb
.QThreshTable
[43];
278 cpi
->pb
.ThisFrameQualityValue
= cpi
->FixedQ
;
280 cpi
->pb
.ThisFrameQualityValue
= cpi
->FixedQ
;
284 /* If the quantizer value has changed then re-initialise it */
285 if ( cpi
->pb
.ThisFrameQualityValue
!= cpi
->pb
.LastFrameQualityValue
) {
286 /* Initialise quality tables. */
287 UpdateQC( cpi
, cpi
->pb
.ThisFrameQualityValue
);
288 cpi
->pb
.LastFrameQualityValue
= cpi
->pb
.ThisFrameQualityValue
;
292 void CopyBackExtraFrags(CP_INSTANCE
*cpi
){
294 unsigned char * SrcPtr
;
295 unsigned char * DestPtr
;
296 ogg_uint32_t PlaneLineStep
;
297 ogg_uint32_t PixelIndex
;
299 /* Copy back for Y plane. */
300 PlaneLineStep
= cpi
->pb
.info
.width
;
301 for ( i
= 0; i
< cpi
->pb
.YPlaneFragments
; i
++ ) {
302 /* We are only interested in updated fragments. */
303 if ( cpi
->extra_fragments
[i
] ) {
304 /* Get the start index for the fragment. */
305 PixelIndex
= cpi
->pb
.pixel_index_table
[i
];
306 SrcPtr
= &cpi
->yuv1ptr
[PixelIndex
];
307 DestPtr
= &cpi
->ConvDestBuffer
[PixelIndex
];
309 for ( j
= 0; j
< VFRAGPIXELS
; j
++ ) {
310 memcpy( DestPtr
, SrcPtr
, HFRAGPIXELS
);
312 SrcPtr
+= PlaneLineStep
;
313 DestPtr
+= PlaneLineStep
;
318 /* Now the U and V planes */
319 PlaneLineStep
= cpi
->pb
.info
.width
/ 2;
320 for ( i
= cpi
->pb
.YPlaneFragments
;
321 i
< (cpi
->pb
.YPlaneFragments
+ (2 * cpi
->pb
.UVPlaneFragments
)) ;
324 /* We are only interested in updated fragments. */
325 if ( cpi
->extra_fragments
[i
] ) {
326 /* Get the start index for the fragment. */
327 PixelIndex
= cpi
->pb
.pixel_index_table
[i
];
328 SrcPtr
= &cpi
->yuv1ptr
[PixelIndex
];
329 DestPtr
= &cpi
->ConvDestBuffer
[PixelIndex
];
331 for ( j
= 0; j
< VFRAGPIXELS
; j
++ ) {
332 memcpy( DestPtr
, SrcPtr
, HFRAGPIXELS
);
333 SrcPtr
+= PlaneLineStep
;
334 DestPtr
+= PlaneLineStep
;