diff mbox series

[FFmpeg-devel,27/35] avcodec/proresenc_anatoliy: remove TO_GOLOMB2()

Message ID 20231211014429.1841681-28-u@pkh.me
State Accepted
Commit e87bc5641ce64df6bd00871ba7ada8a94db90c68
Headers show
Series [FFmpeg-devel,01/35] avcodec/proresenc_kostya: remove an unnecessary parenthesis level in MAKE_CODE() macro | expand

Commit Message

Clément Bœsch Dec. 11, 2023, 1:35 a.m. UTC
A few cosmetics aside, this makes the function identical to the one with
the same name in proresenc_kostya.
---
 libavcodec/proresenc_anatoliy.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

Comments

Stefano Sabatini Dec. 23, 2023, 11:43 p.m. UTC | #1
On date Monday 2023-12-11 02:35:28 +0100, Clément Bœsch wrote:
> A few cosmetics aside, this makes the function identical to the one with
> the same name in proresenc_kostya.
> ---
>  libavcodec/proresenc_anatoliy.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c
> index bdf7bface4..aed5c68b1b 100644
> --- a/libavcodec/proresenc_anatoliy.c
> +++ b/libavcodec/proresenc_anatoliy.c
> @@ -257,7 +257,6 @@ static void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
>  
>  #define GET_SIGN(x)  ((x) >> 31)
>  #define MAKE_CODE(x) (((x) * 2) ^ GET_SIGN(x))
> -#define TO_GOLOMB2(val,sign) ((val)==0 ? 0 : ((val) << 1) + (sign))
>  
>  static av_always_inline int get_level(int val)
>  {
> @@ -271,7 +270,6 @@ static void encode_dcs(PutBitContext *pb, int16_t *blocks,
>  {
>      int i;
>      int codebook = 5, code, dc, prev_dc, delta, sign, new_sign;
> -    int diff_sign;
>  
>      prev_dc = (blocks[0] - 0x4000) / scale;
>      encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
> @@ -282,8 +280,8 @@ static void encode_dcs(PutBitContext *pb, int16_t *blocks,
>          dc        = (blocks[0] - 0x4000) / scale;
>          delta     = dc - prev_dc;
>          new_sign  = GET_SIGN(delta);

> -        diff_sign = new_sign ^ sign;
> -        code      = TO_GOLOMB2(get_level(delta), diff_sign);
> +        delta     = (delta ^ sign) - sign;
> +        code      = MAKE_CODE(delta);

These don't look equivalent,

MAKE_CODE((delta ^ sign) - sign) is equivalent to
TO_GOLOMB2(get_level(delta), sign)

not to
TO_GOLOMB2(get_level(delta), diff_sign)
Clément Bœsch Jan. 7, 2024, 11 p.m. UTC | #2
On Sun, Dec 24, 2023 at 12:43:32AM +0100, Stefano Sabatini wrote:
> On date Monday 2023-12-11 02:35:28 +0100, Clément Bœsch wrote:
> > A few cosmetics aside, this makes the function identical to the one with
> > the same name in proresenc_kostya.
> > ---
> >  libavcodec/proresenc_anatoliy.c | 6 ++----
> >  1 file changed, 2 insertions(+), 4 deletions(-)
> > 
> > diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c
> > index bdf7bface4..aed5c68b1b 100644
> > --- a/libavcodec/proresenc_anatoliy.c
> > +++ b/libavcodec/proresenc_anatoliy.c
> > @@ -257,7 +257,6 @@ static void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
> >  
> >  #define GET_SIGN(x)  ((x) >> 31)
> >  #define MAKE_CODE(x) (((x) * 2) ^ GET_SIGN(x))
> > -#define TO_GOLOMB2(val,sign) ((val)==0 ? 0 : ((val) << 1) + (sign))
> >  
> >  static av_always_inline int get_level(int val)
> >  {
> > @@ -271,7 +270,6 @@ static void encode_dcs(PutBitContext *pb, int16_t *blocks,
> >  {
> >      int i;
> >      int codebook = 5, code, dc, prev_dc, delta, sign, new_sign;
> > -    int diff_sign;
> >  
> >      prev_dc = (blocks[0] - 0x4000) / scale;
> >      encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
> > @@ -282,8 +280,8 @@ static void encode_dcs(PutBitContext *pb, int16_t *blocks,
> >          dc        = (blocks[0] - 0x4000) / scale;
> >          delta     = dc - prev_dc;
> >          new_sign  = GET_SIGN(delta);
> 
> > -        diff_sign = new_sign ^ sign;
> > -        code      = TO_GOLOMB2(get_level(delta), diff_sign);
> > +        delta     = (delta ^ sign) - sign;
> > +        code      = MAKE_CODE(delta);
> 
> These don't look equivalent,
> 
> MAKE_CODE((delta ^ sign) - sign) is equivalent to
> TO_GOLOMB2(get_level(delta), sign)
> 
> not to
> TO_GOLOMB2(get_level(delta), diff_sign)

OK so this one is a bit tricky.

Let's start from the specs, which states that the signed integer to symbol
(code) mapping should be:

    2|n|    if n>=0
    2|n|-1  if n<0

We also know that n>>31 is -1 if n < 0, and 0 if n>=0, which means the
above condition can be simplified to:

    2|n| + (n>>31)

With prores_aw we have:

    s = -1 if different sign, 0 otherwise
    2|n| + s
 
Because:
- get_level() is an absolute function¹
- the val==0 case doesn't matter because in this case s will also be 0

In prores_ks we have:

    n'=-n if different sign, n otherwise
    (2n')^sign(n') <=> 2|n'|-(n'>>31)

So basically, aw does use the comparison with the previous delta and
encodes it accordingly, while ks decides to swap the sign of n according
to that previous delta, then encode it using its new sign.

I wouldn't mind a third pair of eyes on the matter, but these look
equivalent to me.

Note that in practice I also tried to encode a bunch of frames from
testsrc2 with and without the patch, and they are bit identical.

¹ I mis-replied earlier directly to Stefano in the get_level() patch, so
the explanation for why get_leve() is equivalent to the absolute value:
sign can only be -1 (if val < 0) or 0 (if val >= 0). Which means val^sign
will either swap all bits or do nothing. And then it's pretty much what
can be found here:
https://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
Stefano Sabatini Jan. 9, 2024, 11:08 p.m. UTC | #3
On date Monday 2024-01-08 00:00:37 +0100, Clément Bœsch wrote:
> On Sun, Dec 24, 2023 at 12:43:32AM +0100, Stefano Sabatini wrote:
> > On date Monday 2023-12-11 02:35:28 +0100, Clément Bœsch wrote:
> > > A few cosmetics aside, this makes the function identical to the one with
> > > the same name in proresenc_kostya.
> > > ---
> > >  libavcodec/proresenc_anatoliy.c | 6 ++----
> > >  1 file changed, 2 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c
> > > index bdf7bface4..aed5c68b1b 100644
> > > --- a/libavcodec/proresenc_anatoliy.c
> > > +++ b/libavcodec/proresenc_anatoliy.c
> > > @@ -257,7 +257,6 @@ static void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
> > >  
> > >  #define GET_SIGN(x)  ((x) >> 31)
> > >  #define MAKE_CODE(x) (((x) * 2) ^ GET_SIGN(x))
> > > -#define TO_GOLOMB2(val,sign) ((val)==0 ? 0 : ((val) << 1) + (sign))
> > >  
> > >  static av_always_inline int get_level(int val)
> > >  {
> > > @@ -271,7 +270,6 @@ static void encode_dcs(PutBitContext *pb, int16_t *blocks,
> > >  {
> > >      int i;
> > >      int codebook = 5, code, dc, prev_dc, delta, sign, new_sign;
> > > -    int diff_sign;
> > >  
> > >      prev_dc = (blocks[0] - 0x4000) / scale;
> > >      encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
> > > @@ -282,8 +280,8 @@ static void encode_dcs(PutBitContext *pb, int16_t *blocks,
> > >          dc        = (blocks[0] - 0x4000) / scale;
> > >          delta     = dc - prev_dc;
> > >          new_sign  = GET_SIGN(delta);
> > 
> > > -        diff_sign = new_sign ^ sign;
> > > -        code      = TO_GOLOMB2(get_level(delta), diff_sign);
> > > +        delta     = (delta ^ sign) - sign;
> > > +        code      = MAKE_CODE(delta);
> > 
> > These don't look equivalent,
> > 
> > MAKE_CODE((delta ^ sign) - sign) is equivalent to
> > TO_GOLOMB2(get_level(delta), sign)
> > 
> > not to
> > TO_GOLOMB2(get_level(delta), diff_sign)
> 
> OK so this one is a bit tricky.
> 
> Let's start from the specs, which states that the signed integer to symbol
> (code) mapping should be:
> 
>     2|n|    if n>=0
>     2|n|-1  if n<0
> 
> We also know that n>>31 is -1 if n < 0, and 0 if n>=0, which means the
> above condition can be simplified to:
> 
>     2|n| + (n>>31)
> 
> With prores_aw we have:
> 
>     s = -1 if different sign, 0 otherwise
>     2|n| + s
>  
> Because:
> - get_level() is an absolute function¹
> - the val==0 case doesn't matter because in this case s will also be 0
> 
> In prores_ks we have:
> 
>     n'=-n if different sign, n otherwise
>     (2n')^sign(n') <=> 2|n'|-(n'>>31)
> 
> So basically, aw does use the comparison with the previous delta and
> encodes it accordingly, while ks decides to swap the sign of n according
> to that previous delta, then encode it using its new sign.
> 
> I wouldn't mind a third pair of eyes on the matter, but these look
> equivalent to me.
> 
> Note that in practice I also tried to encode a bunch of frames from
> testsrc2 with and without the patch, and they are bit identical.

Thanks for the detailed explanation, I think it's safe to push
especially considering that there are no output changes.
diff mbox series

Patch

diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c
index bdf7bface4..aed5c68b1b 100644
--- a/libavcodec/proresenc_anatoliy.c
+++ b/libavcodec/proresenc_anatoliy.c
@@ -257,7 +257,6 @@  static void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
 
 #define GET_SIGN(x)  ((x) >> 31)
 #define MAKE_CODE(x) (((x) * 2) ^ GET_SIGN(x))
-#define TO_GOLOMB2(val,sign) ((val)==0 ? 0 : ((val) << 1) + (sign))
 
 static av_always_inline int get_level(int val)
 {
@@ -271,7 +270,6 @@  static void encode_dcs(PutBitContext *pb, int16_t *blocks,
 {
     int i;
     int codebook = 5, code, dc, prev_dc, delta, sign, new_sign;
-    int diff_sign;
 
     prev_dc = (blocks[0] - 0x4000) / scale;
     encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
@@ -282,8 +280,8 @@  static void encode_dcs(PutBitContext *pb, int16_t *blocks,
         dc        = (blocks[0] - 0x4000) / scale;
         delta     = dc - prev_dc;
         new_sign  = GET_SIGN(delta);
-        diff_sign = new_sign ^ sign;
-        code      = TO_GOLOMB2(get_level(delta), diff_sign);
+        delta     = (delta ^ sign) - sign;
+        code      = MAKE_CODE(delta);
 
         encode_vlc_codeword(pb, ff_prores_dc_codebook[codebook], code);