[XviD-devel] quant functions b0rked

Edouard Gomez ed.gomez at free.fr
Wed Jul 16 21:26:51 CEST 2003


Edouard Gomez (ed.gomez at free.fr) wrote:
> The errors comes from the asumption (sign(DC) = 0 if DC>0, 1 otherwise)
> sign(DC)*dcscaler/2 == sign(DC) xor dcscaler/2.

Oops, i misunderstood that part of the code, in reality it's just
fine. The bogus code is the last part of dc quantization.

So far the algorithm for this pseudo code:
if(dc<0) dc -= dcscaler/2;
else dc += dcscaler/2;

And it's wrong there:
dc *= ((1<<16)/dcscaler + 1);
dc >>= 16;

Here's the  concerned ASM code extracted from  the quantization function
and turned into  and independent function that is  supposed to scale the
DC coefficient only:

       ;; int scale_dc_only(int32_t coeff, int32_t dscaler);
       ;; We assume:
       ;; sign(x) == 0 if x >= 0
       ;; sign(x) == 1 if x <  0
align 4
int_div
dd 0
%assign i 1
%rep 255 
     dd  (1 << 16) / (i)
     %assign i i+1
%endrep

align ALIGN
cglobal scale_dc_only_asm
scale_dc_only_asm:
        push    ebp
        push    edi

        mov     eax, [esp + 8 + 4]      ; eax = coeff
        mov     ebp, [esp + 8 + 8]      ; ebp = dscaler
        mov     edi, eax                ; edi = coeff
        sar     edi, 31                 ; edi = sign(coeff)..sign(coeff)
        shr     ebp, 1                  ; ebp = dscaler/2
        xor     ebp, edi                ; ebp = (sign(coeff)?-1:1)*dscaler/2 - sign(coeff)
        sub     eax, edi                ; eax = coeff + sign(coeff)
        lea     eax, [byte eax + ebp]   ; eax = coeff + (sign(coeff)?-1:1)*dscaler/2
        mov     edi, [esp + 8 + 8]      ; edi = dscaler

;; The bogus step is here
        imul    eax, [int_div+4*edi]    ; /!\ should be eax = eax / dscaler
        sar     eax, 16
;; End of the bogus step

        pop     edi
        pop     ebp

        ret

The C code that we would like to mimic is:

int32_t scale_dc_only_c(int32_t coeff, int32_t dcscaler)
{
        double p;

        p = coeff;
        p /= dcscaler;
        if(p<0) p -= 0.5f;
        else p += 0.5f;

        return((int32_t)p);
}

Ok, that's  where i am atm, if  some asm guru finds  the solution, email
email... i'm not so good at rounding issues.

-- 
Edouard Gomez


More information about the XviD-devel mailing list