Log in

View Full Version : What info is carried between I frames in CRF mode?


omion
25th April 2006, 11:06
I'm making a distributed-encoder program for x264, and I've gotten pretty far with the first pass. However, I ran into a small problem/strangeness when encoding chunks out of a movie.

Basically, If I did two encodings: one from the first I frame and one from the second I-frame (using the --seek option) there were differences between the encodings.

Even though the QP for all the overlapping frames would be the same, some other things would be different. An example:
Starting from 0 | --seek 67
frame= 64 QP=23 Slice:B size=11425 |
frame= 65 QP=21 Slice:P size=15985 |
frame= 66 QP=21 Slice:P size=17080 |
frame= 67 QP=18 Slice:I size=54697 | frame= 0 QP=18 Slice:I size=54696
frame= 68 QP=21 Slice:P size=36015 | frame= 1 QP=21 Slice:P size=36078
frame= 69 QP=23 Slice:B size=22360 | frame= 2 QP=23 Slice:B size=22566
frame= 70 QP=21 Slice:P size=37255 | frame= 3 QP=21 Slice:P size=37262
frame= 71 QP=21 Slice:P size=37799 | frame= 4 QP=21 Slice:P size=37769
frame= 72 QP=21 Slice:P size=34447 | frame= 5 QP=21 Slice:P size=34417
frame= 73 QP=23 Slice:B size=31303 | frame= 6 QP=23 Slice:B size=31207
frame= 74 QP=21 Slice:P size=31827 | frame= 7 QP=21 Slice:P size=31915
frame= 75 QP=21 Slice:P size=44472 | frame= 8 QP=21 Slice:P size=44569
frame= 76 QP=23 Slice:B size=30729 | frame= 9 QP=23 Slice:B size=30748
frame= 77 QP=21 Slice:P size=41246 | frame= 10 QP=21 Slice:P size=41280
frame= 78 QP=23 Slice:B size=30227 | frame= 11 QP=23 Slice:B size=30243
frame= 79 QP=21 Slice:P size=37784 | frame= 12 QP=21 Slice:P size=37893
frame= 80 QP=21 Slice:P size=36100 | frame= 13 QP=21 Slice:P size=36041

In all of my encodes the first frame of the file is always 1 byte smaller than the same frame in the other file. The differences last until the next I-frame, and everything else seems to be the same.

I was under the impression that the rate control only changed the QP and nothing else. But the same I-frame with the same QP has a different result, making the whole scene different. Is there any way to make them the same?

This is fairly important, as my program needs to encode a lot of one-scene pieces in order to stitch the other pieces together properly. If the result of the small encodes is not the same as one large encode, then it's not very useful...
Since it seems that everything after that one scene is OK, I suppose I could encode two scenes and throw out the first one, but that would be quite a waste.

Any help?

Mug Funky
25th April 2006, 16:00
are these I-frames or IDR frames? because i believe after a plain i-frame you can have reference frames from the GOP before, whereas after an IDR frame you can't use references from the previous GOP.

omion
25th April 2006, 22:42
They are IDR frames. What I was talking about is not that frames after the IDR frame reference those before it, but that x264 uses some data from previous scenes to determine something about the current scene.

akupenguin
26th April 2006, 04:17
The 1 byte in the IDR-frame is simply idr_pic_id, which is incremented at each gop and written with a vlc. So id #1 takes more bits than id #0.

That said, the selection of qp for I-frames does depend on previous frames: it's an offset from the rolling average of P-frames' qps, except for the first I-frame which depends only on the value of --crf.

And that still doesn't explain why the P and B-frames differed while using the same qps. Did you enable --nr? That also keeps track of stuff across gop boundaries.

omion
26th April 2006, 05:21
The 1 byte in the IDR-frame is simply idr_pic_id, which is incremented at each gop and written with a vlc. So id #1 takes more bits than id #0.
That makes sense.

That said, the selection of qp for I-frames does depend on previous frames: it's offset from the rolling average of P-frames' qps, except for the first I-frame which depends only on the value of --crf.Ah. I just did a test where the QP was different. That makes my life a bit more difficult...

And that still doesn't explain why the P and B-frames differed while using the same qps. Did you enable --nr? That also keeps track of stuff across gop boundaries, but does not apply in I-frames.
Oops. I did. I didn't even bother to check that since I never have it on. This time, though, I had "--nr 1" in there.:p
Tried it again without --nr or "--direct auto" (it came out different) and the resultant frames are exactly the same. Well, the first frame has a lot more "misc" bits, but I assume that's due to the option string embedded in the file.

Well, that answers my question, but the fact that splitting at an I-frame might result in different QPs is... bad. At least for me right now. Exactly how weighted is the rolling average? I assume it's a standard exponential moving average like:
new_average = (1 - a) * old_average + a * new_qp
If so, then what is used for a?
If I knew that, then I can figure out how many frames to calculate before the I frame in order to assure the same average.


I'm looking through ratecontrol.c and it looks like it's actually the average of all the QPs of the P-frames since the previous I frame (with the f_ip_factor calculated in). Is this correct?

akupenguin
26th April 2006, 06:37
Yes, it's an exponential moving average with a = 0.05

In 2pass it works differently: the average is run backwards over time, so that an I-frame's qp depends on the P-frames in its own gop. In this method, it's strictly limited to one gop (and still exponentially weighted).

The 2pass method gives better qps, and would fix your independence requirement... but can't work in 1pass. Well, it would possible with sufficient buffering, but I haven't written it yet.