The HTML5 VideoElement allows for codecs informations in the type
property. For once, even safari seems to happily support it. How is it important? Because browsers will choose the first input they can play solely depending on the type
property (or file extension, if absent). Once they make the wrong choice (i.e. A too high level mp4 video for iOS/ a low end android), they’ll just hang there forever.
However, the codecs infos are really not so well documented. I made detailed search on the subject and here are all the bytes you could need to describe your h.264 presets.
Introduction
an h.264 video is described as :
<source src="/path/to/video.mp4" type='video/mp4 codecs="avc1.4D401F"'>
avc1
being h.264’s reference. the 3 hex bytes after the dot are :
- profile_idc
- constraint_set
- level_idc
hereafter you’ll find a complete description of their meaning.
Byte 1 : profile_idc
in h.264 syntax, profile is usually given as a string. For example using libav or ffmpeg, we’ll set it with -profile:v high
. libx264’s code has a simple if chain to parse those (in common/common.c
)
We can get the corresponding integer in common/set.h
so here is the complete translation from profile string to profile_idc
profile | enum | idc |
baseline | 66 | 42 |
main | 77 | 4D |
high | 100 | 64 |
high10 | 110 | 6E |
high422 | 122 | 7A |
high444 | 244 | 7A |
Byte 2 : constraint_set
Again from the code :
A bit more difficult to read but in the end pretty straightforward. The tricky thing here is given how these are written in headers, constraint_set0
is the highest order bit.
b_constraint_set0 to b_constraint_set5 and 2 reserved bytes. The code tells us constraint_set2 is never used. Also, 4 and 5 are not implemented in libx264. The last 4 bytes are written as :
bs_write( s, 4, 0 ); /* reserved */
so we have this mask : xx0x0000
0 and 1 are easy to figure out :
Having PROFILE_MAIN, we get : constraint_set1=1
any higher profile would yield constraint_set1=0
. ``constraint_set0` is set only when using PROFILE_BASELINE.
Then constraint_set3 is set if level_idc is 9 AND profile is BASELINE or MAIN. or : *keyint_max = 1 and profile_idc is HIGH or more**
Easy to figure out if you know your encoding options. If not, any tool would give those results.
A quick look at common/set.c
tells us that bits 4 and 5 are treated as the other reserved.
profile | bits | byte |
baseline | 11000000 | 0xC0 |
main | 01000000 | 0x40 |
high | 00000000 | 0x00 |
high(intra) | 00010000 | 0x10 |
Note : ** this changes if your level_idc is **9 and profile <= MAIN
. Check later section and add 0x10
if it’s the case.
Byte 3 : level_idc
We have 2 syntaxes for levels. 4.1 or 41 means the same thing. The code speaks for itself :
1b is a special case that yields a 9. Other values are converted
So we just take our level and convert it to hex.
Conclusion
For a standard h.264 Main Concept level 3.1 video, your codec code would be : avc1.4D401F
. For any other stream, you can then infer the bytes from your encoding options.