diff --git a/examples/heif_enc.cc b/examples/heif_enc.cc index e36577dcdf..3cf64dd6ba 100644 --- a/examples/heif_enc.cc +++ b/examples/heif_enc.cc @@ -96,6 +96,7 @@ uint32_t sequence_repetitions = 1; std::string vmt_metadata_file; bool binary_metadata_track = false; std::string metadata_track_uri = "vmt:metadata"; +const uint32_t BAD_VMT_TIMESTAMP = 0xFFFFFFFE; int quality = 50; bool lossless = false; @@ -2189,6 +2190,44 @@ static std::vector hex_to_binary(const std::string& line) } +uint32_t parse_vmt_timestamp(const std::string& vmt_time) +{ + std::regex pattern(R"(-?((\d*):)?(\d\d):(\d\d)(\.(\d*))?)"); + std::smatch match; + + if (!std::regex_match(vmt_time, match, pattern)) { + return 0; // no match + } + + std::string hh = match[2]; // optional + std::string mm = match[3]; + std::string ss = match[4]; + std::string fs = match[6]; // optional + + if (vmt_time.find('-') != std::string::npos) { + return 0; // negative time not supported + } + + uint32_t ms = 0; + + if (fs != "") { + if (fs.length() == 3) { + ms = std::stoi(fs); + } + else { + return BAD_VMT_TIMESTAMP; // invalid + } + } + + uint32_t ts = ((hh != "" ? std::stoi(hh) : 0) * 3600 * 1000 + + std::stoi(mm) * 60 * 1000 + + std::stoi(ss) * 1000 + + ms); + + return ts; +} + + int encode_vmt_metadata_track(heif_context* context, heif_track* visual_track, const std::string& track_uri, bool binary) { @@ -2205,7 +2244,7 @@ int encode_vmt_metadata_track(heif_context* context, heif_track* visual_track, std::ifstream istr(vmt_metadata_file.c_str()); - std::regex pattern(R"((\d\d):(\d\d):(\d\d).(\d\d\d) -->$)"); + std::regex pattern(R"(^\s*(-?(\d|:|\.)*)\s*-->\s*(-?(\d|:|\.)*)?)"); static std::vector prev_metadata; static std::optional prev_ts; @@ -2219,15 +2258,10 @@ int encode_vmt_metadata_track(heif_context* context, heif_track* visual_track, continue; } - std::string hh = match[1]; - std::string mm = match[2]; - std::string ss = match[3]; - std::string mil = match[4]; + std::string cue_start = match[1]; + std::string cue_end = match[3]; // == "" for unbounded cues - uint32_t ts = (std::stoi(hh) * 3600 * 1000 + - std::stoi(mm) * 60 * 1000 + - std::stoi(ss) * 1000 + - std::stoi(mil)); + uint32_t ts = parse_vmt_timestamp(cue_start); std::vector concat; @@ -2255,14 +2289,26 @@ int encode_vmt_metadata_track(heif_context* context, heif_track* visual_track, concat.push_back(0); } - if (prev_ts) { - heif_raw_sequence_sample_set_data(sample, (const uint8_t*)prev_metadata.data(), prev_metadata.size()); - heif_raw_sequence_sample_set_duration(sample, ts - *prev_ts); - heif_track_add_raw_sequence_sample(track, sample); - } + if (ts != BAD_VMT_TIMESTAMP) { - prev_ts = ts; - prev_metadata = concat; + if (ts > *prev_ts) { + heif_raw_sequence_sample_set_data(sample, (const uint8_t*)prev_metadata.data(), prev_metadata.size()); + heif_raw_sequence_sample_set_duration(sample, ts - *prev_ts); + heif_track_add_raw_sequence_sample(track, sample); + } + else if (ts == *prev_ts) { + concat.insert(concat.begin(), prev_metadata.begin(), prev_metadata.end()); + } + else { + std::cerr << "Bad VMT timestamp order: " << cue_start << "\n"; + } + + prev_ts = ts; + prev_metadata = concat; + } + else { + std::cerr << "Bad VMT timestamp: " << cue_start << "\n"; + } } // --- flush last metadata packet