mirror of
				https://github.com/kunkundi/crossdesk.git
				synced 2025-10-26 20:25:34 +08:00 
			
		
		
		
	[feat] refactor h264 frame assember
This commit is contained in:
		
							
								
								
									
										123
									
								
								src/media/video/assemble_frame/h264_frame_assember.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/media/video/assemble_frame/h264_frame_assember.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | |||||||
|  | #include "h264_frame_assember.h" | ||||||
|  |  | ||||||
|  | H264FrameAssembler::H264FrameAssembler() {} | ||||||
|  |  | ||||||
|  | H264FrameAssembler::~H264FrameAssembler() {} | ||||||
|  |  | ||||||
|  | int64_t EuclideanMod(int64_t n, int64_t div) { | ||||||
|  |   return (n %= div) < 0 ? n + div : n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename T> | ||||||
|  | inline bool AheadOrAt(T a, T b) { | ||||||
|  |   const T maxDist = std::numeric_limits<T>::max() / 2 + T(1); | ||||||
|  |   if (a - b == maxDist) return b < a; | ||||||
|  |   return b - a < maxDist; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int64_t* GetContinuousSequence( | ||||||
|  |     std::array<int64_t, MAX_TRACKED_SEQUENCE_SIZE>& last_continuous, | ||||||
|  |     int64_t unwrapped_seq_num) { | ||||||
|  |   for (int64_t& last : last_continuous) { | ||||||
|  |     if (unwrapped_seq_num - 1 == last) { | ||||||
|  |       return &last; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int64_t H264FrameAssembler::Unwrap(uint16_t seq_num) { | ||||||
|  |   return (int64_t)seq_num; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::vector<std::unique_ptr<RtpPacketH264>>& H264FrameAssembler::InsertPacket( | ||||||
|  |     std::unique_ptr<RtpPacketH264> rtp_packet) { | ||||||
|  |   std::vector<std::unique_ptr<RtpPacketH264>> result; | ||||||
|  |  | ||||||
|  |   int64_t unwrapped_seq_num = Unwrap(rtp_packet->SequenceNumber()); | ||||||
|  |   auto& packet_slotted = GetPacketFromBuffer(unwrapped_seq_num); | ||||||
|  |   if (packet_slotted != nullptr && | ||||||
|  |       AheadOrAt(packet_slotted->Timestamp(), rtp_packet->Timestamp())) { | ||||||
|  |     // The incoming `packet` is old or a duplicate. | ||||||
|  |     return std::move(result); | ||||||
|  |   } else { | ||||||
|  |     packet_slotted = std::move(rtp_packet); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return std::move(FindFrames(unwrapped_seq_num)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::unique_ptr<RtpPacketH264>& H264FrameAssembler::GetPacketFromBuffer( | ||||||
|  |     int64_t unwrapped_seq_num) { | ||||||
|  |   return packet_buffer_[EuclideanMod(unwrapped_seq_num, | ||||||
|  |                                      MAX_PACKET_BUFFER_SIZE)]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::vector<std::unique_ptr<RtpPacketH264>> H264FrameAssembler::FindFrames( | ||||||
|  |     int64_t unwrapped_seq_num) { | ||||||
|  |   std::vector<std::unique_ptr<RtpPacketH264>> result; | ||||||
|  |   RtpPacketH264* packet_slotted = GetPacketFromBuffer(unwrapped_seq_num).get(); | ||||||
|  |  | ||||||
|  |   int64_t* last_continuous_unwrapped_seq_num = | ||||||
|  |       GetContinuousSequence(last_continuous_in_sequence_, unwrapped_seq_num); | ||||||
|  |  | ||||||
|  |   // not continuous or the beginning of a new coded video sequence. | ||||||
|  |   if (last_continuous_unwrapped_seq_num == nullptr) { | ||||||
|  |     // if (packet_slotted->FuAStart()) { | ||||||
|  |     //   return result; | ||||||
|  |     // } | ||||||
|  |  | ||||||
|  |     last_continuous_in_sequence_[last_continuous_in_sequence_index_] = | ||||||
|  |         unwrapped_seq_num; | ||||||
|  |     last_continuous_unwrapped_seq_num = | ||||||
|  |         &last_continuous_in_sequence_[last_continuous_in_sequence_index_]; | ||||||
|  |     last_continuous_in_sequence_index_ = | ||||||
|  |         (last_continuous_in_sequence_index_ + 1) % | ||||||
|  |         last_continuous_in_sequence_.size(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (int64_t seq_num = unwrapped_seq_num; | ||||||
|  |        seq_num < unwrapped_seq_num + MAX_PACKET_BUFFER_SIZE;) { | ||||||
|  |     // Packets that were never assembled into a completed frame will stay in | ||||||
|  |     // the 'buffer_'. Check that the `packet` sequence number match the expected | ||||||
|  |     // unwrapped sequence number. | ||||||
|  |     if (seq_num != Unwrap(packet_slotted->SequenceNumber())) { | ||||||
|  |       return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     *last_continuous_unwrapped_seq_num = seq_num; | ||||||
|  |     // Last packet of the frame, try to assemble the frame. | ||||||
|  |     if (packet_slotted->FuAEnd()) { | ||||||
|  |       uint32_t rtp_timestamp = packet_slotted->Timestamp(); | ||||||
|  |  | ||||||
|  |       // Iterate backwards to find where the frame starts. | ||||||
|  |       for (int64_t seq_num_start = seq_num; | ||||||
|  |            seq_num_start > seq_num - MAX_PACKET_BUFFER_SIZE; --seq_num_start) { | ||||||
|  |         auto& prev_packet = GetPacketFromBuffer(seq_num_start - 1); | ||||||
|  |  | ||||||
|  |         if (prev_packet == nullptr || | ||||||
|  |             prev_packet->Timestamp() != rtp_timestamp) { | ||||||
|  |           const auto& current_packet = GetPacketFromBuffer(seq_num_start); | ||||||
|  |           if (!current_packet->FuAStart()) { | ||||||
|  |             // First packet of the frame is missing. | ||||||
|  |             return result; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           for (int64_t seq_num = seq_num_start; seq_num <= seq_num; ++seq_num) { | ||||||
|  |             auto& packet = GetPacketFromBuffer(seq_num); | ||||||
|  |             result.push_back(std::move(packet)); | ||||||
|  |           } | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     seq_num++; | ||||||
|  |     packet_slotted = GetPacketFromBuffer(seq_num).get(); | ||||||
|  |     if (packet_slotted == nullptr) { | ||||||
|  |       return result; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								src/media/video/assemble_frame/h264_frame_assember.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/media/video/assemble_frame/h264_frame_assember.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | /* | ||||||
|  |  * @Author: DI JUNKUN | ||||||
|  |  * @Date: 2025-03-26 | ||||||
|  |  * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef _H264_FRAME_ASSEMBER_H_ | ||||||
|  | #define _H264_FRAME_ASSEMBER_H_ | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  |  | ||||||
|  | #include "rtp_packet_h264.h" | ||||||
|  |  | ||||||
|  | #define MAX_PACKET_BUFFER_SIZE 2048 | ||||||
|  | #define MAX_TRACKED_SEQUENCE_SIZE 5 | ||||||
|  |  | ||||||
|  | class H264FrameAssembler { | ||||||
|  |  public: | ||||||
|  |   H264FrameAssembler(); | ||||||
|  |   ~H264FrameAssembler(); | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |   std::vector<std::unique_ptr<RtpPacketH264>>& InsertPacket( | ||||||
|  |       std::unique_ptr<RtpPacketH264> rtp_packet); | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   int64_t Unwrap(uint16_t seq_num); | ||||||
|  |  | ||||||
|  |   std::unique_ptr<RtpPacketH264>& GetPacketFromBuffer( | ||||||
|  |       int64_t unwrapped_seq_num); | ||||||
|  |  | ||||||
|  |   std::vector<std::unique_ptr<RtpPacketH264>> FindFrames( | ||||||
|  |       int64_t unwrapped_seq_num); | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   std::array<std::unique_ptr<RtpPacketH264>, MAX_PACKET_BUFFER_SIZE> | ||||||
|  |       packet_buffer_; | ||||||
|  |   std::array<int64_t, MAX_TRACKED_SEQUENCE_SIZE> last_continuous_in_sequence_; | ||||||
|  |   int64_t last_continuous_in_sequence_index_ = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
| @@ -248,7 +248,7 @@ class RtpPacket { | |||||||
|     return rtp::PAYLOAD_TYPE(payload_type_); |     return rtp::PAYLOAD_TYPE(payload_type_); | ||||||
|   } |   } | ||||||
|   uint16_t SequenceNumber() const { return sequence_number_; } |   uint16_t SequenceNumber() const { return sequence_number_; } | ||||||
|   uint64_t Timestamp() const { return timestamp_; } |   uint32_t Timestamp() const { return timestamp_; } | ||||||
|   uint32_t Ssrc() const { return ssrc_; } |   uint32_t Ssrc() const { return ssrc_; } | ||||||
|   std::vector<uint32_t> Csrcs() const { return csrcs_; }; |   std::vector<uint32_t> Csrcs() const { return csrcs_; }; | ||||||
|   uint16_t ExtensionProfile() const { return extension_profile_; } |   uint16_t ExtensionProfile() const { return extension_profile_; } | ||||||
|   | |||||||
| @@ -329,7 +329,7 @@ class RtpPacket { | |||||||
|     // ParseRtpData(); |     // ParseRtpData(); | ||||||
|     return sequence_number_; |     return sequence_number_; | ||||||
|   } |   } | ||||||
|   uint64_t Timestamp() const { |   uint32_t Timestamp() const { | ||||||
|     // ParseRtpData(); |     // ParseRtpData(); | ||||||
|     return timestamp_; |     return timestamp_; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -195,6 +195,27 @@ void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet) { | |||||||
|     ProcessAv1RtpPacket(rtp_packet_av1); |     ProcessAv1RtpPacket(rtp_packet_av1); | ||||||
|   } else if (rtp_packet.PayloadType() == rtp::PAYLOAD_TYPE::H264 || |   } else if (rtp_packet.PayloadType() == rtp::PAYLOAD_TYPE::H264 || | ||||||
|              rtp_packet.PayloadType() == rtp::PAYLOAD_TYPE::H264 - 1) { |              rtp_packet.PayloadType() == rtp::PAYLOAD_TYPE::H264 - 1) { | ||||||
|  |     // std::unique_ptr<RtpPacketH264> rtp_packet_h264 = | ||||||
|  |     //     std::make_unique<RtpPacketH264>(); | ||||||
|  |     // if (rtp_packet_h264->Build(rtp_packet.Buffer().data(), | ||||||
|  |     // rtp_packet.Size())) { | ||||||
|  |     //   std::vector<std::unique_ptr<RtpPacketH264>> complete_frame = std::move( | ||||||
|  |     //       h264_frame_assembler_.InsertPacket(std::move(rtp_packet_h264))); | ||||||
|  |     //   if (!complete_frame.empty()) { | ||||||
|  |     //     for (auto& frame : complete_frame) { | ||||||
|  |     //       ReceivedFrame received_frame(frame->Payload(), | ||||||
|  |     //       frame->PayloadSize()); | ||||||
|  |     //       received_frame.SetReceivedTimestamp(clock_->CurrentTime().us()); | ||||||
|  |     //       received_frame.SetCapturedTimestamp( | ||||||
|  |     //           (static_cast<int64_t>(frame->Timestamp()) / | ||||||
|  |     //                rtp::kMsToRtpTimestamp - | ||||||
|  |     //            delta_ntp_internal_ms_) * | ||||||
|  |     //           1000); | ||||||
|  |     //       compelete_video_frame_queue_.push(received_frame); | ||||||
|  |     //     } | ||||||
|  |     //   } | ||||||
|  |     // } | ||||||
|  |  | ||||||
|     RtpPacketH264 rtp_packet_h264; |     RtpPacketH264 rtp_packet_h264; | ||||||
|     if (rtp_packet_h264.Build(rtp_packet.Buffer().data(), rtp_packet.Size())) { |     if (rtp_packet_h264.Build(rtp_packet.Buffer().data(), rtp_packet.Size())) { | ||||||
|       rtp_packet_h264.GetFrameHeaderInfo(); |       rtp_packet_h264.GetFrameHeaderInfo(); | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ | |||||||
| #include "api/clock/clock.h" | #include "api/clock/clock.h" | ||||||
| #include "clock/system_clock.h" | #include "clock/system_clock.h" | ||||||
| #include "fec_decoder.h" | #include "fec_decoder.h" | ||||||
|  | #include "h264_frame_assember.h" | ||||||
| #include "io_statistics.h" | #include "io_statistics.h" | ||||||
| #include "nack_requester.h" | #include "nack_requester.h" | ||||||
| #include "receive_side_congestion_controller.h" | #include "receive_side_congestion_controller.h" | ||||||
| @@ -125,6 +126,7 @@ class RtpVideoReceiver : public ThreadBase, | |||||||
|       missing_sequence_numbers_; |       missing_sequence_numbers_; | ||||||
|   std::unordered_map<uint64_t, uint16_t> fua_end_sequence_numbers_; |   std::unordered_map<uint64_t, uint16_t> fua_end_sequence_numbers_; | ||||||
|   std::unordered_map<uint64_t, int64_t> missing_sequence_numbers_wait_time_; |   std::unordered_map<uint64_t, int64_t> missing_sequence_numbers_wait_time_; | ||||||
|  |   H264FrameAssembler h264_frame_assembler_; | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   std::thread rtcp_thread_; |   std::thread rtcp_thread_; | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ target("transport") | |||||||
|  |  | ||||||
| target("media") | target("media") | ||||||
|     set_kind("object") |     set_kind("object") | ||||||
|     add_deps("log", "frame", "common") |     add_deps("log", "frame", "common", "rtp") | ||||||
|     if is_os("windows") then |     if is_os("windows") then | ||||||
|         add_files("src/media/video/encode/*.cpp", |         add_files("src/media/video/encode/*.cpp", | ||||||
|         "src/media/video/decode/*.cpp", |         "src/media/video/decode/*.cpp", | ||||||
| @@ -214,10 +214,12 @@ target("media") | |||||||
|     end |     end | ||||||
|     add_files("src/media/audio/encode/*.cpp", |     add_files("src/media/audio/encode/*.cpp", | ||||||
|         "src/media/audio/decode/*.cpp", |         "src/media/audio/decode/*.cpp", | ||||||
|         "src/media/resolution_adapter/*.cpp") |         "src/media/resolution_adapter/*.cpp", | ||||||
|  |         "src/media/video/assemble_frame/*.cpp") | ||||||
|     add_includedirs("src/media/audio/encode", |     add_includedirs("src/media/audio/encode", | ||||||
|         "src/media/audio/decode", |         "src/media/audio/decode", | ||||||
|         "src/media/resolution_adapter", |         "src/media/resolution_adapter", | ||||||
|  |         "src/media/video/assemble_frame", | ||||||
|         "src/interface", {public = true}) |         "src/interface", {public = true}) | ||||||
|  |  | ||||||
| target("pc") | target("pc") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user