diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 5ac86f91d..f1bf7c098 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -1680,50 +1680,9 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket* pkt) { srs_error_t err = srs_success; - // For OBS WHIP, it uses RTP Raw packet with SPS/PPS/IDR frame. Note that not all - // raw payload is SPS/PPS. - bool has_sps_pps_in_raw_payload = false; - SrsRtpRawPayload* raw_payload = dynamic_cast(pkt->payload()); - if (raw_payload) { - if (pkt->nalu_type == SrsAvcNaluTypeSPS) { - has_sps_pps_in_raw_payload = true; - srs_freep(obs_whip_sps_); - obs_whip_sps_ = pkt->copy(); - } else if (pkt->nalu_type == SrsAvcNaluTypePPS) { - has_sps_pps_in_raw_payload = true; - srs_freep(obs_whip_pps_); - obs_whip_pps_ = pkt->copy(); - } - // Ignore if one of OBS WHIP SPS/PPS is not ready. - if (has_sps_pps_in_raw_payload && (!obs_whip_sps_ || !obs_whip_pps_)) { - return err; - } - } - - // Generally, there will be SPS+PPS+IDR in a STAP-A packet. - SrsRtpSTAPPayload* stap_payload = dynamic_cast(pkt->payload()); - - // Handle SPS/PPS in cache or STAP-A packet. - if (stap_payload || has_sps_pps_in_raw_payload) { - // Get the SPS/PPS from cache or STAP-A packet. - SrsSample* sps = stap_payload ? stap_payload->get_sps() : NULL; - if (!sps && obs_whip_sps_) sps = dynamic_cast(obs_whip_sps_->payload())->sample_; - SrsSample* pps = stap_payload ? stap_payload->get_pps() : NULL; - if (!pps && obs_whip_pps_) pps = dynamic_cast(obs_whip_pps_->payload())->sample_; - if (!sps || !pps) { - return srs_error_new(ERROR_RTC_RTP_MUXER, "no sps or pps in stap-a rtp. sps: %p, pps:%p", sps, pps); - } - - // Packet SPS/PPS to RTMP keyframe. - err = packet_sps_pps(pkt, sps, pps); - - // Always reset the SPS/PPS cache after used it. - srs_freep(obs_whip_sps_); - srs_freep(obs_whip_pps_); - - if (err != srs_success) { - return srs_error_wrap(err, "packet sps/pps"); - } + err = packet_sequence_header_avc(pkt); + if (err != srs_success) { + return srs_error_wrap(err, "packet video key frame"); } if (-1 == rtp_key_frame_ts_) { @@ -1779,7 +1738,60 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket* pkt) return err; } -srs_error_t SrsRtcFrameBuilder::packet_sps_pps(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps) +srs_error_t SrsRtcFrameBuilder::packet_sequence_header_avc(SrsRtpPacket* pkt) +{ + srs_error_t err = srs_success; + + // For OBS WHIP, it uses RTP Raw packet with SPS/PPS/IDR frame. Note that not all + // raw payload is SPS/PPS. + bool has_sps_pps_in_raw_payload = false; + SrsRtpRawPayload* raw_payload = dynamic_cast(pkt->payload()); + if (raw_payload) { + if (pkt->nalu_type == SrsAvcNaluTypeSPS) { + has_sps_pps_in_raw_payload = true; + srs_freep(obs_whip_sps_); + obs_whip_sps_ = pkt->copy(); + } else if (pkt->nalu_type == SrsAvcNaluTypePPS) { + has_sps_pps_in_raw_payload = true; + srs_freep(obs_whip_pps_); + obs_whip_pps_ = pkt->copy(); + } + // Ignore if one of OBS WHIP SPS/PPS is not ready. + if (has_sps_pps_in_raw_payload && (!obs_whip_sps_ || !obs_whip_pps_)) { + return err; + } + } + + // Generally, there will be SPS+PPS+IDR in a STAP-A packet. + SrsRtpSTAPPayload* stap_payload = dynamic_cast(pkt->payload()); + + // Handle SPS/PPS in cache or STAP-A packet. + if (stap_payload || has_sps_pps_in_raw_payload) { + // Get the SPS/PPS from cache or STAP-A packet. + SrsSample* sps = stap_payload ? stap_payload->get_sps() : NULL; + if (!sps && obs_whip_sps_) sps = dynamic_cast(obs_whip_sps_->payload())->sample_; + SrsSample* pps = stap_payload ? stap_payload->get_pps() : NULL; + if (!pps && obs_whip_pps_) pps = dynamic_cast(obs_whip_pps_->payload())->sample_; + if (!sps || !pps) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "no sps or pps in stap-a rtp. sps: %p, pps:%p", sps, pps); + } + + // Packet SPS/PPS to RTMP keyframe. + err = do_packet_sequence_header_avc(pkt, sps, pps); + + // Always reset the SPS/PPS cache after used it. + srs_freep(obs_whip_sps_); + srs_freep(obs_whip_pps_); + + if (err != srs_success) { + return srs_error_wrap(err, "packet sps/pps"); + } + } + + return err; +} + +srs_error_t SrsRtcFrameBuilder::do_packet_sequence_header_avc(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 13e03efb0..50eaa80f0 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -356,7 +356,8 @@ private: private: srs_error_t packet_video(SrsRtpPacket* pkt); srs_error_t packet_video_key_frame(SrsRtpPacket* pkt); - srs_error_t packet_sps_pps(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps); + srs_error_t packet_sequence_header_avc(SrsRtpPacket* pkt); + srs_error_t do_packet_sequence_header_avc(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps); private: inline uint16_t cache_index(uint16_t current_sn) { return current_sn % s_cache_size; diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index ba2ebddae..01a4c28b8 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -946,21 +946,16 @@ srs_error_t SrsRtpPacket::decode(SrsBuffer* buf) return err; } -bool SrsRtpPacket::is_keyframe() +// Helper function to check if H.264 RTP packet is a keyframe +bool srs_rtp_packet_h264_is_keyframe(uint8_t nalu_type, ISrsRtpPayloader* payload) { - // False if audio packet - if(SrsFrameTypeAudio == frame_type) { - return false; - } - - // It's normal H264 video rtp packet if (nalu_type == kStapA) { - SrsRtpSTAPPayload* stap_payload = dynamic_cast(payload_); + SrsRtpSTAPPayload* stap_payload = dynamic_cast(payload); if(NULL != stap_payload->get_sps() || NULL != stap_payload->get_pps()) { return true; } } else if (nalu_type == kFuA) { - SrsRtpFUAPayload2* fua_payload = dynamic_cast(payload_); + SrsRtpFUAPayload2* fua_payload = dynamic_cast(payload); if(SrsAvcNaluTypeIDR == fua_payload->nalu_type) { return true; } @@ -968,28 +963,56 @@ bool SrsRtpPacket::is_keyframe() if((SrsAvcNaluTypeIDR == nalu_type) || (SrsAvcNaluTypeSPS == nalu_type) || (SrsAvcNaluTypePPS == nalu_type)) { return true; } -#ifdef SRS_H265 - if(nalu_type == kStapHevc) { - SrsRtpSTAPPayloadHevc* stap_payload = dynamic_cast(payload_); - if(NULL != stap_payload->get_vps() || NULL != stap_payload->get_sps() || NULL != stap_payload->get_pps()) { - return true; - } - } else if(nalu_type == kFuHevc) { - SrsRtpFUAPayloadHevc2* fua_payload = dynamic_cast(payload_); - if(fua_payload->nalu_type >= SrsHevcNaluType_CODED_SLICE_BLA && fua_payload->nalu_type <= SrsHevcNaluType_RESERVED_23) { - return true; - } - } else { - if((SrsHevcNaluType_VPS == nalu_type) || (SrsHevcNaluType_SPS == nalu_type) || (SrsHevcNaluType_PPS == nalu_type)) { - return true; - } - } -#endif } return false; } +#ifdef SRS_H265 +// Helper function to check if H.265 RTP packet is a keyframe +bool srs_rtp_packet_h265_is_keyframe(uint8_t nalu_type, ISrsRtpPayloader* payload) +{ + if(nalu_type == kStapHevc) { + SrsRtpSTAPPayloadHevc* stap_payload = dynamic_cast(payload); + if(NULL != stap_payload->get_vps() || NULL != stap_payload->get_sps() || NULL != stap_payload->get_pps()) { + return true; + } + } else if(nalu_type == kFuHevc) { + SrsRtpFUAPayloadHevc2* fua_payload = dynamic_cast(payload); + if(fua_payload->nalu_type >= SrsHevcNaluType_CODED_SLICE_BLA && fua_payload->nalu_type <= SrsHevcNaluType_RESERVED_23) { + return true; + } + } else { + if((SrsHevcNaluType_VPS == nalu_type) || (SrsHevcNaluType_SPS == nalu_type) || (SrsHevcNaluType_PPS == nalu_type)) { + return true; + } + } + + return false; +} +#endif + +bool SrsRtpPacket::is_keyframe() +{ + // False if audio packet + if(SrsFrameTypeAudio == frame_type) { + return false; + } + + // Check H.264 keyframe types + if (nalu_type == kStapA || nalu_type == kFuA || + nalu_type == SrsAvcNaluTypeIDR || nalu_type == SrsAvcNaluTypeSPS || nalu_type == SrsAvcNaluTypePPS) { + return srs_rtp_packet_h264_is_keyframe(nalu_type, payload_); + } + +#ifdef SRS_H265 + // Check H.265 keyframe types + return srs_rtp_packet_h265_is_keyframe(nalu_type, payload_); +#else + return false; +#endif +} + SrsRtpRawPayload::SrsRtpRawPayload() { payload = NULL;