Add support for libx265 playback on iPhone and other MAC devices

Hello
Why do I need to run this ffmpeg line to make libx265 to work on my videos?
This should be added in other maybe? tag=hvc1 or something

This fixes the issue in 2 seconds even on hours long movies:
ffmpeg -i MyMovie.mp4 -c:v copy -tag:v hvc1 -c:a copy MyMovieFixed.mp4

Hope there is another way to do this in the program

hvc1 and hev1 are two different things.

hvc1 is HEVC video with the metadata for decoding it stored only in the container (meaning not in the video stream).

hev1 is the FFmpeg default tag, which indicates an HEVC video where metadata can be stored in the container or the stream.

Basically, Apple is the inflexible party here by insisting that metadata be stored only in the container. Or more likely, their insistence on signaling that metadata is only in the container, whether it is actually there or not.

People have already asked the FFmpeg developers to make hvc1 the default tag. The developers declined. They didn’t give their reasoning, but my guess would be that they did not (or could not) guarantee that metadata would only appear in the container to be hvc1 compliant. Note that libx265 is a separate software project from FFmpeg, with separate developers.

See request at FFmpeg bug tracker:
#6860 (hvc1 instead of hev1 in FourCC) – FFmpeg

In light of this, I think it would be dangerous to make the current Shotcut HEVC stock export presets use the hvc1 tag as a default. Perhaps it might be viable to create an additional HEVC export preset where the phrase “for Apple devices” is clearly indicated in the title for those willing to take the risk with hvc1. (This is just my opinion… I’m in no position to say what will actually happen.)

For now, the best solution is to make a custom export preset as @MusicalBox demonstrated and add vtag=hvc1 to the list before saving it. This would remove the need to run ffmpeg after export to add the tag manually. As a convenience, also adding meta.preset.extension=mp4 to the Other box would set the default extension to .mp4 so you wouldn’t have to add it yourself at every export.


For the uber-curious, note what happens in the metadata with the hvc1 override…

The container metadata:
ffprobe -i test.mp4 -show_format

[FORMAT]
filename=test.mp4
nb_streams=2
nb_programs=0
format_name=mov,mp4,m4a,3gp,3g2,mj2
format_long_name=QuickTime / MOV
start_time=0.000000
duration=10.048000
size=776763
bit_rate=618441
probe_score=100
TAG:major_brand=isom
TAG:minor_version=512
TAG:compatible_brands=isomiso2mp41
TAG:encoder=Lavf58.29.100
[/FORMAT]

…which doesn’t contain much decoding metadata. Most of it is still in the stream (note the codec_tag_string=hvc1 override)…

ffprobe -i test.mp4 -show_entries stream

[STREAM]
index=0
codec_name=hevc
codec_long_name=H.265 / HEVC (High Efficiency Video Coding)
profile=Main 10
codec_type=video
codec_tag_string=hvc1
codec_tag=0x31637668
width=1920
height=1080
coded_width=1920
coded_height=1080
closed_captions=0
has_b_frames=2
sample_aspect_ratio=1:1
display_aspect_ratio=16:9
pix_fmt=yuv420p10le
level=120
color_range=tv
color_space=bt709
color_transfer=bt709
color_primaries=bt709
chroma_location=left
field_order=progressive
refs=1
id=N/A
r_frame_rate=30000/1001
avg_frame_rate=30000/1001
time_base=1/30000
start_pts=0
start_time=0.000000
duration_ts=300300
duration=10.010000
bit_rate=606117
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=300
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
DISPOSITION:captions=0
DISPOSITION:descriptions=0
DISPOSITION:metadata=0
DISPOSITION:dependent=0
DISPOSITION:still_image=0
TAG:language=und
TAG:handler_name=VideoHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]

I didn’t take time to compare this file to the ISO spec to be certain, but I’m pretty sure this file does not totally qualify as HVC1-compliant despite the codec_tag_string being overridden to say it is. This is why I don’t think a request to change the default to HVC1 would get any traction… it wouldn’t be correct from a compliance standpoint and could cause problems with more strict playback systems. The fact that the file plays on Mac High Sierra seems to suggest that Apple’s decoder is more forgiving than it lets on, provided the file makes it through the hvc1 checkpoint. Why the checkpoint is still there is anyone’s guess.

3 Likes

While I agree that Apple is being stubborn, for Shotcut I lean towards pragmatism over strict compliance in this area. I understand why FFmpeg would prefer the compliance, but Shotcut is more of a consumer product with an official macOS build.

2 Likes

Yes I have alot of presets and with Austin’s answer I will update all my Apple presets with vtag=hvc1

Thank you
Br,
Knut

Does adding the HVC1 tag also force the inclusion of BT.709 and 10-bit tags or are they taken from the essence?

If it’s originated from and intended for an iPhone I’d expect 8 bit BT.709 or 10 bit BT.2100.

It works as you are expecting. The test file I used did not originate from an iPhone. So you’re right, this looks like an odd combination for an iPhone. Setting the hvc1 tag only sets the FourCC. The colorspace and bit depth were taken from the essence (or could be taken from overridden export settings).

Having said that, the stock HEVC export preset in Shotcut also defaults the output to 10-bit even if pix_fmt=yuv420p10le is not specified in the Advanced > Other box. I’m not sure why it defaults to 10-bit over 8-bit, but I don’t complain since 8-bit HEVC is not always the greatest looking encoding.

That is not intentional, and the default behavior changed at the beginning of this year first appearing in the 20.11.28 release. That coincides with when I changed the build to enable the high bit depth compile option for x265, but I did not realize that is locking FFmpeg into a 10-bit only mode, which seems to be the case even though ffmpeg -h encoder=libx265 seems to suggest otherwise in the list of supported pixel formats. Even when using ffmpeg command line, I face this problem.

OK, I figured out some obscure build magic is required to enable both 8 and 10 bit in libx265, and I am working on the fix for this in the next version 21.09.

1 Like

A small PSA - I usually reuse the same saved preset (in this case, originally using codec x265) by changing settings as needed and the vtag=hvc1 will stay in the Other tab even if changing the codec to x264 and it will FAIL to encode with it present.
It took me by surprise as I didn’t know that this would take effect even for my own presets, not just the default ones.