+void H265Parser::UpdateTimingInfoIfNeeded(
+ std::vector<std::vector<uint8_t>>* spses_array,
+ int num_units_in_tick,
+ int time_scale) {
+ media::H265Parser::Result result;
+
+ for (auto& sps : *spses_array) {
+ // Reset bit reader, skip first 2 bytes with NAL header
+ br_.Initialize(sps.data() + 2, sps.size() - 2);
+ int sps_id = 0;
+ result = ParseSPS(&sps_id);
+ DCHECK(result == media::H265Parser::kOk);
+
+ if (active_sps_.find(sps_id) == active_sps_.end()) {
+ DVLOG(3) << "Error while parsing SPS unit";
+ continue;
+ }
+
+ if (!active_sps_[sps_id]->vui_parameters_present_flag) {
+ DVLOG(1) << "VUI parameters are not present in SPS. "
+ << "Adding framerate information skipped.";
+ continue;
+ }
+
+ if (active_sps_[sps_id]->vui_parameters.timing_info_present_flag) {
+ LOG(INFO) << "VUI timing info present in SPS " << sps_id;
+ continue;
+ }
+
+ auto new_sps =
+ PrepareSPSWithTimingInfo(sps, sps_id, num_units_in_tick, time_scale);
+
+ LOG(INFO) << "Inserting VUI timing info: " << time_scale << '/'
+ << num_units_in_tick << " into SPS " << sps_id;
+
+ sps.swap(new_sps);
+ }
+}
+
+std::vector<uint8_t> H265Parser::PrepareSPSWithTimingInfo(
+ const std::vector<uint8_t>& old_sps,
+ int sps_id,
+ int num_units_in_tick,
+ int time_scale) {
+ const auto& vui_parameters = active_sps_[sps_id]->vui_parameters;
+
+ int bit_offset_from_end = vui_parameters.timing_info_bit_offset_from_nal_end;
+ int currently_processed_bit_index =
+ (bit_offset_from_end - 1 + kBitsInByte) % kBitsInByte;
+ int byte_number =
+ ((old_sps.size() * kBitsInByte) - bit_offset_from_end) / kBitsInByte;
+
+ std::vector<uint8_t> new_sps(old_sps.begin(),
+ std::next(old_sps.begin(), byte_number + 1));
+
+ // SPS will be extended by the following parameters
+ // num_units_in_tick - 4 bytes
+ // time_scale - 4 bytes
+ // vui_poc_proportional_to_timing_flag - 1 bit
+ // vui_hrd_parameters_present_flag - 1 bit
+ //
+ // Summarizing - 4 + 4 + 1 = 9 bytes need to be added
+ new_sps.reserve(old_sps.size() + 9);
+
+ // Enable timing_info_present_flag
+ InsertBitIntoVector(&new_sps, ¤tly_processed_bit_index, &byte_number,
+ 1);
+
+ // Rewritten value of timing_info_present_flag, so offset from end needs to be
+ // decreased
+ --bit_offset_from_end;
+
+ // Add num_units_in_tick value
+ InsertValueIntoVector(&new_sps, ¤tly_processed_bit_index, &byte_number,
+ num_units_in_tick);
+
+ // Add time_scale value
+ InsertValueIntoVector(&new_sps, ¤tly_processed_bit_index, &byte_number,
+ time_scale);
+
+ // Add vui_poc_proportional_to_timing_flag value
+ InsertBitIntoVector(&new_sps, ¤tly_processed_bit_index, &byte_number,
+ 0);
+
+ // Add vui_hrd_parameters_present_flag value
+ InsertBitIntoVector(&new_sps, ¤tly_processed_bit_index, &byte_number,
+ 0);
+
+ // Add remaining values from old_sps
+ for (int offset = bit_offset_from_end; offset > 0; --offset) {
+ int o_byte_number = ((old_sps.size() * kBitsInByte) - offset) / kBitsInByte;
+ int o_byte_value = old_sps[o_byte_number];
+
+ // Don't propagate emulation_prevention_three_byte added to original SPS
+ if (o_byte_number > 1 && !old_sps[o_byte_number - 2] &&
+ !old_sps[o_byte_number - 1] && old_sps[o_byte_number] == 3) {
+ continue;
+ }
+
+ int o_bit_number = (offset - 1 + kBitsInByte) % kBitsInByte;
+ int o_bit_value = (1u << o_bit_number) & o_byte_value;
+ InsertBitIntoVector(&new_sps, ¤tly_processed_bit_index, &byte_number,
+ o_bit_value);
+ }
+
+ // 7.4.2.1 General NAL unit semantics
+ // "The last byte of the NAL unit shall not be equal to 0x00."
+ while (!new_sps.back()) {
+ new_sps.pop_back();
+ }
+
+ return new_sps;
+}
+