ultravideo / kvazaar

An open-source HEVC encoder
BSD 3-Clause "New" or "Revised" License
833 stars 180 forks source link

Chrome on Mac only plays 1 second of encoded video #360

Closed jozefchutka closed 1 year ago

jozefchutka commented 1 year ago

I am using ffmpeg to export hevc video using kvazaar encoder. My command line is actually very simple:

ffmpeg -i input.mp4 -vcodec libkvazaar -tag:v hvc1 output.mp4

The output is playable in QuickTime, however chrome on mac only plays first second.

If libkvazaar is exchanged for libx265 the playback in chrome is ok.

Are there any params to be set for kvazaar to make the video playable?

fador commented 1 year ago

Hi,

Thanks for reporting this.

I didn't know Chrome started supporting HEVC, that's good news! I was also able to reproduce the issue with Chrome playback in Windows. Something weird going with our intra frame insertion what I can tell, -kvazaar-params "period=1" making every frame Intra frame completely destroys the video but if I use -kvazaar-params "period=0" making only the first frame Intra, the rest of the video is played ok.. I have not seen this issue before so I think we have to do some debugging and see what types of frames x265 is inserting..

-Marko

jozefchutka commented 1 year ago

Hi @fador thanks for picking this one up quickly.

is my understanding correct regarding period=0 that it means less compression, but still suitable even for longer videos (has nothing to do with keyframes)?

I have also created crbug https://bugs.chromium.org/p/chromium/issues/detail?id=1458385 and chromium guys are also picking it up quickly, please consider helping them out with your expertise.

fador commented 1 year ago

period=0 is actually better for compression since it means we don't insert any keyframes (other than the first), but it would make rewinding the video hard, not sure how modern players handle that. I would not recommend using it for long videos 🤔

Thank you for creating the issue also to chromium, from the video I can see that the playback issue is exactly the same in my Chrome.

I was toggling all kinds of parameters but didn't find any clues how to fix the issue yet..

Jovasa commented 1 year ago

Well actually, at least on my testing I did couple of years ago when working on automatic scenecut detection, period=0 tends to have a worse compression performance than lets say period=256.

jozefchutka commented 1 year ago

The status update from the chrome team is unfortunately wontfix. However there is some description on whats going on low level and why the consider the stream invalid and needs encoder/muxer level fix:

This is encoder/muxer issue. ISO/IEC 14496-15:2022 section 8.3.1 clearly requires streams with "hvc1“ as the parent sample entry name for hvcC box should be the only place to store parameter sets(SPS/VPS/PPS for H.266); it is only when the sample entry name is "hev1" that the muxer is allowed to put parameter sets in both hvcC box and the sample itself.

Since your stream uses hvc1 as the sample entry name, we will prioritize information in hvcC box. We should not hack this just to make the stream playable. The encoder tool needs to be fixed at least to copy the PPS correctly into hvcC box...

There is some more details starting at https://bugs.chromium.org/p/chromium/issues/detail?id=1458385#c9

I wonder, is this something that can be fixed on kvazaar level or should ffmpeg team be involved?

fador commented 1 year ago

Based on this information I did some more debugging and it is our problem, but basically related to the ffmpeg integration 😅

So the problem itself doesn't seem to be the parameter sets but the fact that they differ. In ffmpeg we give out the parameter sets before we start encoding and it actually causes some of the values to be uninitialized (or not really, they are just initialized to a default which is later changed).

https://github.com/ultravideo/kvazaar/blob/master/src/encoder_state-bitstream.c#L507 Here the max_qp_delta_depth is actually set in https://github.com/ultravideo/kvazaar/blob/master/src/encoderstate.c#L1529 So my solution would be to check for the cfg parameters when writing the flag, I just have to verify that it's done correctly. I will make the fix today after checking everything is correct.

We don't typically work with muxer code and don't know how they handle things so very nice work from the Chromium people to figure out the problem! 😁

fador commented 1 year ago

..and based on this you can actually fix the issue by setting: -kvazaar-params "set-qp-in-cu=1" or -kvazaar-params "vaq=5"

jozefchutka commented 1 year ago

Thanks @fador ,

I have tested set-qp-in-cu=1 and confirm that would fix playback in chrome. However, vaq=5 breaks playback in chrome completely.

Looking forward for the fix.

fador commented 1 year ago

This will hopefully fix the problem, actually the value really was uninitialized so it might actually be a bit random if the header was correct or not. And we can reopen the issue if the problem still remains, are you building the FFmpeg yourself or do we have to wait for some third party to compile a new version?

jozefchutka commented 1 year ago

I am building ffmpeg (.wasm) and will let you know

jozefchutka commented 1 year ago

Tested, all good!

Chrome can play through this video:

ffmpeg -i input.mp4 -vcodec libkvazaar -tag:v hvc1 output.mp4

Thanks for the quick fix.

fador commented 1 year ago

Thank you for reporting this issue, it would have taken us a long time to figure this out without your and the Chromium teams help!