6.25.4 - The record loses its SEI at the door
Drop-in from 6.25.3. One fix on the fMP4 remux path, no API change. Second round on #365, reported and retested by @RomanLiberda: 6.25.0 fixed the sample framing on that path, the file still failed, and this is the next candidate standing on it.
Five NAL types, not three
When a source's config record is Annex B and its packets are Annex B too, the two agree and the record is forwarded as it is. That is deliberate: movenc reads the record to decide whether to convert the samples, and these samples do need converting. What follows from it is that movenc builds the hvcC itself, out of those Annex-B parameter sets, and ff_isom_write_hvcc collects five NAL types rather than three:
static const uint8_t array_idx_to_type[] =
{ HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS,
HEVC_NAL_SEI_PREFIX, HEVC_NAL_SEI_SUFFIX };So a prefix SEI in a Matroska CodecPrivate, which is where x265 leaves its options string, becomes a fourth array in the init sample description. That is the record Apple TV's HEVC track builder rejects: asset.tracks count=0, no format description, the item fails before a frame is decoded. AE#187 is the same shape arriving through the other door.
The defense could not see this door
The engine has stripped non-parameter-set arrays since #187, and that defense sits on the record path: it guards on configurationVersion == 1, which an Annex-B buffer fails by construction, and the record movenc builds is never handled by the engine at all. Between the two of them there was no point at which the finished record was inspected.
The fix drops the non-parameter-set NALs on this side of the muxer and leaves the record in Annex B, so movenc's decision about the samples comes out exactly as before. Only the SEI is gone.
Generalised, because it is not specific to HEVC: a guard keyed on the shape of the input misses the door where the muxer builds the output itself.
Measured
Real 1080p Main10 PQ parameter sets (78 B of NAL payload in total) plus a 506 B user-data SEI, in Annex B, through the same movenc path the session muxer uses, comes back as a record whose arrays are [32, 33, 34, 39]. After the rewrite the same input yields [32, 33, 34].
Diagnostics
The #365 forward branch now names what the record is made of and what it dropped:
#365 ... the muxer builds the config record itself out of 726 B of Annex B
[VPS×1 (28 B), SPS×1 (112 B), PPS×1 (10 B), SEI_PREFIX×1 (570 B)],
dropped the non-parameter-set NALs before it does (→ 156 B, AE#187)
A record's size on its own does not separate a large SPS from an SEI, and only the SEI reaches the hvcC.
Not claimed
The file behind #365 has not been retested against this yet and its record has never been seen here. If that line comes back saying nothing to drop, this is not that file's defect and the DV configuration boxes in the init are next in line.
Two readings from the round-1 retest were checked against the code and do not hold, both narrowing the search rather than widening it. All four arms of the #35 readiness-gate ladder read the same init.mp4, because the ladder swaps the playlist URL in place and the reduced master is a playlist and not a second remux, so the DV-stripped arm failing identically rules out the playlist signalling and nothing about the init. And hvcc_add_nal_unit drops every NAL with nuh_layer_id > 0 unless it is writing an lhvC box, so enhancement-layer parameter sets cannot reach the record at all, whatever the CodecPrivate carries.