diff --git a/source/encoders/codecs/h264.cpp b/source/encoders/codecs/h264.cpp index c9e39e6..5ca26e2 100644 --- a/source/encoders/codecs/h264.cpp +++ b/source/encoders/codecs/h264.cpp @@ -20,3 +20,68 @@ // SOFTWARE. #include "h264.hpp" + +uint8_t* is_nal_start(uint8_t* ptr, uint8_t* end_ptr, size_t& size) +{ + // Ensure that the remaining space actually can contain a prefix and NAL header. + if ((ptr + (3 + 1)) >= end_ptr) + return nullptr; + + if (*ptr != 0x0) + return nullptr; + if (*(ptr + 1) != 0x0) + return nullptr; + + // 3-Byte NAL prefix. + if (*(ptr + 2) == 0x1) { + size = 3; + return ptr + 3; + } + + // 4-Byte NAL Prefix + if ((ptr + (4 + 1)) >= end_ptr) + return nullptr; + if (*(ptr + 2) != 0x0) + return nullptr; + if (*(ptr + 3) != 0x01) + return nullptr; + + size = 4; + return ptr + 4; +} + +uint8_t* streamfx::encoder::codec::h264::find_closest_nal(uint8_t* ptr, uint8_t* end_ptr, size_t& size) +{ + for (uint8_t* seek_ptr = ptr; seek_ptr < end_ptr; seek_ptr++) { + if (auto nal_ptr = is_nal_start(seek_ptr, end_ptr, size); nal_ptr != nullptr) + return nal_ptr; + } + return nullptr; +} + +uint32_t streamfx::encoder::codec::h264::get_packet_reference_count(uint8_t* ptr, uint8_t* end_ptr) +{ + size_t nal_ptr_prefix = 0; + uint8_t* nal_ptr = find_closest_nal(ptr, end_ptr, nal_ptr_prefix); + while ((nal_ptr != nullptr) && (nal_ptr < end_ptr)) { + // Try and figure out the actual size of the NAL. + size_t nal_end_ptr_prefix = 0; + uint8_t* nal_end_ptr = find_closest_nal(nal_ptr, end_ptr, nal_end_ptr_prefix); + size_t nal_size = (nal_end_ptr ? nal_end_ptr : end_ptr) - nal_ptr - nal_end_ptr_prefix; + + // Try and figure out the ideal priority. + switch (static_cast((*nal_ptr) & 0x5)) { + case nal_unit_type::CODED_SLICE_NONIDR: + return (*nal_ptr >> 5) & 0x2; + case nal_unit_type::CODED_SLICE_IDR: + return (*nal_ptr >> 5) & 0x2; + default: + break; + } + + // Update our NAL pointer. + nal_ptr = nal_end_ptr; + } + + return std::numeric_limits::max(); +} diff --git a/source/encoders/codecs/h264.hpp b/source/encoders/codecs/h264.hpp index 0d85810..607a667 100644 --- a/source/encoders/codecs/h264.hpp +++ b/source/encoders/codecs/h264.hpp @@ -60,4 +60,40 @@ namespace streamfx::encoder::codec::h264 { L6_2, UNKNOWN = -1, }; + + // See ITU-T H.264 + enum class nal_unit_type : uint8_t { + UNSPECIFIED = 0, + CODED_SLICE_NONIDR = 1, + CODED_SLICE_DATA_PARTITION_A = 2, + CODED_SLICE_DATA_PARTITION_B = 3, + CODED_SLICE_DATA_PARTITION_C = 4, + CODED_SLICE_IDR = 5, + SUPPLEMENTAL_ENHANCEMENT_INFORMATION = 6, + SEQUENCE_PARAMETER_SET = 7, + PICTURE_PARAMETER_SET = 8, + ACCESS_UNIT_DELIMITER = 9, + END_OF_SEQUENCE = 10, + END_OF_STREAM = 11, + FILLER_DATA = 12, + SEQUENCE_PARAMETER_SET_EXTENSION = 13, + PREFIX_NAL_UNIT = 14, + SUBSET_SEQUENCE_PARAMETER_SET = 15, + DEPTH_PARAMETER_SET = 16, + CODED_SLICE_AUXILIARY_PICTURE = 19, + CODED_SLICE_EXTENSION = 20, + CODED_SLICE_EXTENSION_DEPTH_VIEW = 21, + }; + + /** Search for the closest NAL unit. + * + * \param ptr Beginning of the search range. + * \param endptr End of the search range (exclusive). + * + * \return A valid pointer if a NAL was found, otherwise \ref nullptr. + */ + uint8_t* find_closest_nal(uint8_t* ptr, uint8_t* endptr, size_t& size); + + uint32_t get_packet_reference_count(uint8_t* ptr, uint8_t* endptr); + } // namespace streamfx::encoder::codec::h264