Skip to content

Commit 7c1262e

Browse files
committed
Normalize compatible HEVC fragmented tracks to hvc1
1 parent 5acc4dc commit 7c1262e

3 files changed

Lines changed: 457 additions & 2 deletions

File tree

src/cmaf_segmenter.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,59 @@ const TrackDescription* fragment_track_description(const Mp4Box& moof,
100100
return nullptr;
101101
}
102102

103+
void patch_sample_entry_type(std::vector<std::uint8_t>& init_bytes, const TrackDescription& track, std::size_t track_index) {
104+
const std::vector<Mp4Box> top_level_boxes = parse_mp4_boxes(init_bytes);
105+
const Mp4Box* moov = find_first_box(top_level_boxes, "moov");
106+
if (moov == nullptr) {
107+
return;
108+
}
109+
110+
std::size_t trak_index = 0;
111+
for (const auto& child : moov->children) {
112+
if (child.type != "trak") {
113+
continue;
114+
}
115+
116+
const Mp4Box* tkhd = find_child_box(child, "tkhd");
117+
std::uint32_t child_track_id = 0;
118+
if (tkhd != nullptr && tkhd->payload.size >= 20) {
119+
const std::uint8_t version = init_bytes[tkhd->payload.offset];
120+
const std::size_t track_id_offset = tkhd->payload.offset + (version == 1 ? 20 : 12);
121+
if (track_id_offset + 4 <= init_bytes.size()) {
122+
child_track_id = read_be32(init_bytes, track_id_offset);
123+
}
124+
}
125+
126+
const bool matches = track.track_id != 0 ? child_track_id == track.track_id : trak_index == track_index;
127+
++trak_index;
128+
if (!matches) {
129+
continue;
130+
}
131+
132+
const Mp4Box* mdia = find_child_box(child, "mdia");
133+
const Mp4Box* minf = mdia == nullptr ? nullptr : find_child_box(*mdia, "minf");
134+
const Mp4Box* stbl = minf == nullptr ? nullptr : find_child_box(*minf, "stbl");
135+
const Mp4Box* stsd = stbl == nullptr ? nullptr : find_child_box(*stbl, "stsd");
136+
if (stsd == nullptr || stsd->payload.size < 16) {
137+
return;
138+
}
139+
140+
const std::size_t sample_entry_type_offset = stsd->payload.offset + 12;
141+
if (sample_entry_type_offset + 4 > init_bytes.size() || track.sample_entry_type.size() != 4) {
142+
return;
143+
}
144+
145+
std::copy(track.sample_entry_type.begin(), track.sample_entry_type.end(), init_bytes.begin() + sample_entry_type_offset);
146+
return;
147+
}
148+
}
149+
150+
void patch_init_segment_sample_entries(std::vector<std::uint8_t>& init_bytes, const std::vector<TrackDescription>& tracks) {
151+
for (std::size_t index = 0; index < tracks.size(); ++index) {
152+
patch_sample_entry_type(init_bytes, tracks[index], index);
153+
}
154+
}
155+
103156
std::uint64_t read_be64(std::span<const std::uint8_t> bytes, std::size_t offset) {
104157
std::uint64_t value = 0;
105158
for (int index = 0; index < 8; ++index) {
@@ -542,6 +595,7 @@ std::vector<std::uint8_t> build_fragmented_init_segment(const Mp4Box& ftyp,
542595
}
543596

544597
init.insert(init.end(), moov_bytes.begin(), moov_bytes.end());
598+
patch_init_segment_sample_entries(init, tracks);
545599
return init;
546600
}
547601

@@ -804,6 +858,7 @@ SegmentedMp4 segment_for_cmaf(const ParsedMp4& parsed_mp4, CmafObjectMode object
804858
segmented.initialization_segment.owned_bytes.assign(
805859
slice_bytes(parsed_mp4.bytes, segmented.initialization_segment.span).begin(),
806860
slice_bytes(parsed_mp4.bytes, segmented.initialization_segment.span).end());
861+
patch_init_segment_sample_entries(segmented.initialization_segment.owned_bytes, parsed_mp4.tracks);
807862
segmented.initialization_segment.span = {};
808863

809864
if (moofs.size() != mdats.size()) {

0 commit comments

Comments
 (0)