Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 62 additions & 16 deletions examples/heif_enc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2189,6 +2190,44 @@ static std::vector<uint8_t> 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)
{
Expand All @@ -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<uint8_t> prev_metadata;
static std::optional<uint32_t> prev_ts;
Expand All @@ -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<uint8_t> concat;

Expand Down Expand Up @@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it legal input to have similar timestamps following each other?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - for several reasons, including:

  • two VMT cues may share the same start time and have different end times
  • two VMT cues that share the same start times and end times may have different cue ids or carry different payloads that are agnostic of each other
  • where negative cue times are not supported, a simple workaround is to set those negative values to zero (destructively) which may produce unexpected duplicate times

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
Expand Down