diff mbox series

[FFmpeg-devel,1/3] lavc/h274: fix PRNG definition

Message ID 20230927135617.33952-1-ffmpeg@haasn.xyz
State Accepted
Commit 338a5fcdbe9571e6f22817a111621259d83f2e59
Headers show
Series [FFmpeg-devel,1/3] lavc/h274: fix PRNG definition | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Niklas Haas Sept. 27, 2023, 1:56 p.m. UTC
From: Niklas Haas <git@haasn.dev>

The spec specifies x^31 + x^3 + 1 as the polynomial, but the diagram in
Figure 1-1 omits the +1 offset. The initial implementation was based on
the diagram, but this is wrong (produces subtly incorrect results).
---
 libavcodec/h274.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Niklas Haas Sept. 27, 2023, 2:10 p.m. UTC | #1
Context: I compared our implementation against a H.274 reference stream.
Identified this issues as a result.

This is still not bit-exact, we round incorrectly in some cases (~2% of
output pixels are +1 or -1). I'm not sure where we pick up the remaining
error from..
Michael Niedermayer Sept. 27, 2023, 7:07 p.m. UTC | #2
On Wed, Sep 27, 2023 at 03:56:15PM +0200, Niklas Haas wrote:
> From: Niklas Haas <git@haasn.dev>
> 
> The spec specifies x^31 + x^3 + 1 as the polynomial, but the diagram in
> Figure 1-1 omits the +1 offset. The initial implementation was based on
> the diagram, but this is wrong (produces subtly incorrect results).
> ---
>  libavcodec/h274.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/libavcodec/h274.c b/libavcodec/h274.c
> index a69f9411429..fc111cdb50d 100644
> --- a/libavcodec/h274.c
> +++ b/libavcodec/h274.c
> @@ -38,7 +38,7 @@ static void prng_shift(uint32_t *state)
>  {
>      // Primitive polynomial x^31 + x^3 + 1 (modulo 2)
>      uint32_t x = *state;
> -    uint8_t feedback = (x >> 2) ^ (x >> 30);
> +    uint8_t feedback = 1u ^ (x >> 2) ^ (x >> 30);
>      *state = (x << 1) | (feedback & 1u);

where can i find the text describing this that you refer to ?

thx

[...]
Niklas Haas Sept. 28, 2023, 3:07 p.m. UTC | #3
On Wed, 27 Sep 2023 21:07:55 +0200 Michael Niedermayer <michael@niedermayer.cc> wrote:
> where can i find the text describing this that you refer to ?

It is in SMPTE RDD 5 (DOI 10.5594/SMPTE.RDD5.2006), you can find it on
the usual places.
Vittorio Giovara Sept. 28, 2023, 4:03 p.m. UTC | #4
On Thu, Sep 28, 2023 at 11:08 AM Niklas Haas <ffmpeg@haasn.xyz> wrote:

> On Wed, 27 Sep 2023 21:07:55 +0200 Michael Niedermayer <
> michael@niedermayer.cc> wrote:
> > where can i find the text describing this that you refer to ?
>
> It is in SMPTE RDD 5 (DOI 10.5594/SMPTE.RDD5.2006), you can find it on
> the usual places.
>

Could it maybe be mentioned in the commit log? Or documented in a comment
(not familiar with the file, apologies if it's already so)
Michael Niedermayer Sept. 28, 2023, 6:53 p.m. UTC | #5
On Wed, Sep 27, 2023 at 03:56:15PM +0200, Niklas Haas wrote:
> From: Niklas Haas <git@haasn.dev>
> 
> The spec specifies x^31 + x^3 + 1 as the polynomial, but the diagram in
> Figure 1-1 omits the +1 offset. The initial implementation was based on
> the diagram, but this is wrong (produces subtly incorrect results).

the +1 changes "nothing"
if you take the prng with and without the +1 the 2 will produce 2
sequences that are negations of each other

or said different if you start one from 1 and the other from ~1
they will produce the same sequence just 0 and 1 swaped

you can also compute 32 bits at once using this:
(this needs 64bits of the sequence as input though)
not sure how useful it is, but it produces more bits quicker

 static void prng_shift32(uint64_t *state)
 {
     uint64_t x = *state;
     uint64_t y = x ^ x>>3;
     y ^= y>>6;
     y ^= y>>12;
     uint32_t feedback = (x >> 1) ^ (y >> 5) ^ (x >> 29) ^ (x >> 30);
     *state = (x << 32) | feedback;
 }


[...]
Niklas Haas Sept. 28, 2023, 7:17 p.m. UTC | #6
On Thu, 28 Sep 2023 20:53:44 +0200 Michael Niedermayer <michael@niedermayer.cc> wrote:
> On Wed, Sep 27, 2023 at 03:56:15PM +0200, Niklas Haas wrote:
> > From: Niklas Haas <git@haasn.dev>
> > 
> > The spec specifies x^31 + x^3 + 1 as the polynomial, but the diagram in
> > Figure 1-1 omits the +1 offset. The initial implementation was based on
> > the diagram, but this is wrong (produces subtly incorrect results).
> 
> the +1 changes "nothing"
> if you take the prng with and without the +1 the 2 will produce 2
> sequences that are negations of each other
> 
> or said different if you start one from 1 and the other from ~1
> they will produce the same sequence just 0 and 1 swaped
> 
> you can also compute 32 bits at once using this:
> (this needs 64bits of the sequence as input though)
> not sure how useful it is, but it produces more bits quicker
> 
>  static void prng_shift32(uint64_t *state)
>  {
>      uint64_t x = *state;
>      uint64_t y = x ^ x>>3;
>      y ^= y>>6;
>      y ^= y>>12;
>      uint32_t feedback = (x >> 1) ^ (y >> 5) ^ (x >> 29) ^ (x >> 30);
>      *state = (x << 32) | feedback;
>  }

Thanks for the explanation and tip.

In this case, PRNG output is by far not the bottleneck (we only need one
32-bit random value per 16x16 block), so I don't think it needs to be
modified further.
Niklas Haas Sept. 28, 2023, 7:18 p.m. UTC | #7
On Thu, 28 Sep 2023 12:03:08 -0400 Vittorio Giovara <vittorio.giovara@gmail.com> wrote:
> On Thu, Sep 28, 2023 at 11:08 AM Niklas Haas <ffmpeg@haasn.xyz> wrote:
> 
> > On Wed, 27 Sep 2023 21:07:55 +0200 Michael Niedermayer <
> > michael@niedermayer.cc> wrote:
> > > where can i find the text describing this that you refer to ?
> >
> > It is in SMPTE RDD 5 (DOI 10.5594/SMPTE.RDD5.2006), you can find it on
> > the usual places.
> >
> 
> Could it maybe be mentioned in the commit log? Or documented in a comment
> (not familiar with the file, apologies if it's already so)

Hi,

it is mentioned in the commit message attached to the initial
implementation of this file, and also linked multiple times throughout
the source code.
diff mbox series

Patch

diff --git a/libavcodec/h274.c b/libavcodec/h274.c
index a69f9411429..fc111cdb50d 100644
--- a/libavcodec/h274.c
+++ b/libavcodec/h274.c
@@ -38,7 +38,7 @@  static void prng_shift(uint32_t *state)
 {
     // Primitive polynomial x^31 + x^3 + 1 (modulo 2)
     uint32_t x = *state;
-    uint8_t feedback = (x >> 2) ^ (x >> 30);
+    uint8_t feedback = 1u ^ (x >> 2) ^ (x >> 30);
     *state = (x << 1) | (feedback & 1u);
 }