diff --git a/trunk/src/app/srs_app_gb28181.cpp b/trunk/src/app/srs_app_gb28181.cpp index b93bff9e1..3bcd1f91c 100644 --- a/trunk/src/app/srs_app_gb28181.cpp +++ b/trunk/src/app/srs_app_gb28181.cpp @@ -1087,7 +1087,7 @@ srs_error_t SrsGbMuxer::write_h265_vps_sps_pps(uint32_t dts, uint32_t pts) char *flv = NULL; int nb_flv = 0; - if ((err = hevc_->mux_avc2flv(sh, frame_type, hevc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { + if ((err = hevc_->mux_hevc2flv(sh, frame_type, hevc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { return srs_error_wrap(err, "hevc to flv"); } @@ -1131,7 +1131,7 @@ srs_error_t SrsGbMuxer::write_h265_ipb_frame(char *frame, int frame_size, uint32 char *flv = NULL; int nb_flv = 0; - if ((err = hevc_->mux_avc2flv(ipb, frame_type, hevc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { + if ((err = hevc_->mux_hevc2flv(ipb, frame_type, hevc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { return srs_error_wrap(err, "hevc to flv"); } diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index b89064db4..d6ef4f96b 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -2163,7 +2163,7 @@ srs_error_t SrsRtcFrameBuilder::do_packet_sequence_header_hevc(SrsRtpPacket *pkt char *flv = NULL; int nb_flv = 0; - if ((err = hevc->mux_avc2flv_enhanced(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoHEVCFrameTraitPacketTypeSequenceStart, pkt->get_avsync_time(), + if ((err = hevc->mux_hevc2flv_enhanced(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoHEVCFrameTraitPacketTypeSequenceStart, pkt->get_avsync_time(), pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) { return srs_error_wrap(err, "mux sequence header"); } diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index 2e5dd2b86..f57b734c1 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -683,7 +683,7 @@ srs_error_t SrsSrtFrameBuilder::check_vps_sps_pps_change(SrsTsMessage *msg) // h265 packet to flv packet. char *flv = NULL; int nb_flv = 0; - if ((err = hevc->mux_avc2flv_enhanced(sh, + if ((err = hevc->mux_hevc2flv_enhanced(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoHEVCFrameTraitPacketTypeSequenceStart, dts, diff --git a/trunk/src/protocol/srs_protocol_raw_avc.cpp b/trunk/src/protocol/srs_protocol_raw_avc.cpp index 918afdcab..be3558a54 100644 --- a/trunk/src/protocol/srs_protocol_raw_avc.cpp +++ b/trunk/src/protocol/srs_protocol_raw_avc.cpp @@ -564,13 +564,15 @@ srs_error_t SrsRawHEVCStream::mux_ipb_frame(char *frame, int nb_frame, std::stri return err; } -srs_error_t SrsRawHEVCStream::mux_avc2flv(std::string video, int8_t frame_type, int8_t avc_packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv) +srs_error_t SrsRawHEVCStream::mux_hevc2flv(std::string video, int8_t frame_type, int8_t avc_packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv) { srs_error_t err = srs_success; - // for h265 in RTMP video payload, there is 5bytes header: - // 1bytes, FrameType | CodecID - // 1bytes, AVCPacketType + // Non-standard HEVC support using codec ID 12 in FLV video tag. + // This follows the conventional approach adopted by domestic CDN vendors in China. + // For h265 in RTMP video payload, there is 5bytes header: + // 1bytes, FrameType | CodecID (CodecID = 12 for HEVC) + // 1bytes, AVCPacketType (reused from AVC for compatibility) // 3bytes, CompositionTime, the cts. // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 int size = (int)video.length() + 5; @@ -605,11 +607,13 @@ srs_error_t SrsRawHEVCStream::mux_avc2flv(std::string video, int8_t frame_type, return err; } -srs_error_t SrsRawHEVCStream::mux_avc2flv_enhanced(std::string video, int8_t frame_type, int8_t packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv) +srs_error_t SrsRawHEVCStream::mux_hevc2flv_enhanced(std::string video, int8_t frame_type, int8_t packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv) { srs_error_t err = srs_success; - // for h265 in RTMP video payload, there is 5bytes header: + // Standard enhanced-rtmp HEVC support using fourcc 'hvc1'. + // This is the more universal and standardized approach for HEVC in FLV/RTMP. + // For h265 in enhanced-rtmp video payload, there is 5bytes header: // 1bytes, IsExHeader | FrameType | PacketType // 4bytes, Video FourCC. AV1 = { 'a', 'v', '0', '1' } // VP9 = { 'v', 'p', '0', '9' } diff --git a/trunk/src/protocol/srs_protocol_raw_avc.hpp b/trunk/src/protocol/srs_protocol_raw_avc.hpp index f181457a4..d12c792dc 100644 --- a/trunk/src/protocol/srs_protocol_raw_avc.hpp +++ b/trunk/src/protocol/srs_protocol_raw_avc.hpp @@ -89,22 +89,28 @@ public: // @param ibp output the packet. // @param frame_type output the frame type. virtual srs_error_t mux_ipb_frame(char *frame, int nb_frame, std::string &ibp); - // Mux the hevc video packet to flv video packet. + // Mux the hevc video packet to flv video packet using non-standard HEVC codec ID. + // This method uses the conventional approach adopted by domestic CDN vendors in China, + // which adds a new codecID (12) to the FLV video tag for HEVC support. + // NOTE: This is a non-standard extension compared to enhanced-rtmp. + // The enhanced-rtmp approach (mux_hevc2flv_enhanced) is more universal and recommended. // @param frame_type, SrsVideoAvcFrameTypeKeyFrame or SrsVideoAvcFrameTypeInterFrame. // @param avc_packet_type, SrsVideoAvcFrameTraitSequenceHeader or SrsVideoAvcFrameTraitNALU. // @param video the hevc raw data. // @param flv output the muxed flv packet. // @param nb_flv output the muxed flv size. - virtual srs_error_t mux_avc2flv(std::string video, int8_t frame_type, int8_t avc_packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv); - // Mux the hevc video packet to flv video packet, enhanced mode. + virtual srs_error_t mux_hevc2flv(std::string video, int8_t frame_type, int8_t avc_packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv); + // Mux the hevc video packet to flv video packet using enhanced-rtmp standard. + // This method follows the enhanced-rtmp specification, which is the more universal + // and standardized approach for HEVC support in FLV/RTMP streams. + // Enhanced-rtmp uses fourcc 'hvc1' for HEVC codec identification instead of codec ID. + // @see https://veovera.org/docs/enhanced/enhanced-rtmp-v1.pdf // @param packet_type, SrsVideoHEVCFrameTraitPacketTypeSequenceStart or SrsVideoHEVCFrameTraitPacketTypeCodedFrames. // @param frame_type, SrsVideoAvcFrameTypeKeyFrame or SrsVideoAvcFrameTypeInterFrame. // @param video the hevc raw data. // @param flv output the muxed flv packet. // @param nb_flv output the muxed flv size. - // TODO: Rename method to mux_hevc2flv_enhanced since AVC is an alias for H.264, not H.265/HEVC. - // This affects other modules like SRT and GB28181, so should be done in a separate refactoring. - virtual srs_error_t mux_avc2flv_enhanced(std::string video, int8_t frame_type, int8_t packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv); + virtual srs_error_t mux_hevc2flv_enhanced(std::string video, int8_t frame_type, int8_t packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv); }; // The header of adts sample. diff --git a/trunk/src/utest/srs_utest_protocol3.cpp b/trunk/src/utest/srs_utest_protocol3.cpp index d7f185e44..8104f4bb9 100644 --- a/trunk/src/utest/srs_utest_protocol3.cpp +++ b/trunk/src/utest/srs_utest_protocol3.cpp @@ -760,13 +760,13 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxIpbFrame) } } -VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) +VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxHevc2flv) { srs_error_t err = srs_success; SrsRawHEVCStream hevc; - // Test mux_avc2flv with sequence header + // Test mux_hevc2flv with sequence header if (true) { std::string video_data = std::string("\x01\x64\x00\x20\xff\xe1\x00\x19\x67\x64\x00\x20", 12); int8_t frame_type = 1; // keyframe @@ -776,7 +776,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); // Should produce FLV packet with 5-byte header + video data EXPECT_TRUE(flv_data != NULL); @@ -798,7 +798,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) } } - // Test mux_avc2flv with NALU frame + // Test mux_hevc2flv with NALU frame if (true) { std::string video_data = std::string("\x00\x00\x00\x0e\x26\x01\xaf\x06\xb8\x63\xef\x3a\x7f\x3c\x00\x01\x00\x80", 18); int8_t frame_type = 1; // keyframe @@ -808,7 +808,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); EXPECT_EQ(5 + video_data.length(), nb_flv); @@ -822,7 +822,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) } } - // Test mux_avc2flv with inter frame + // Test mux_hevc2flv with inter frame if (true) { std::string video_data = std::string("\x00\x00\x00\x08\x02\x01\xd0\x80\x93\x25\x88\x84", 12); int8_t frame_type = 2; // inter frame @@ -832,7 +832,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); if (flv_data) { @@ -842,7 +842,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) } } - // Test mux_avc2flv with empty video data + // Test mux_hevc2flv with empty video data if (true) { std::string empty_video_data; int8_t frame_type = 1; // keyframe @@ -852,7 +852,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv(empty_video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv(empty_video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); // Should produce FLV packet with 5-byte header only EXPECT_TRUE(flv_data != NULL); @@ -871,7 +871,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) } } - // Test mux_avc2flv with large composition time offset + // Test mux_hevc2flv with large composition time offset if (true) { std::string video_data = std::string("\x00\x00\x00\x04\x26\x01\xaf\x06", 8); int8_t frame_type = 1; // keyframe @@ -881,7 +881,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv(video_data, frame_type, avc_packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); if (flv_data) { @@ -894,13 +894,13 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flv) } } -VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) +VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxHevc2flvEnhanced) { srs_error_t err = srs_success; SrsRawHEVCStream hevc; - // Test mux_avc2flv_enhanced with sequence header + // Test mux_hevc2flv_enhanced with sequence header if (true) { std::string video_data = std::string("\x01\x64\x00\x20\xff\xe1\x00\x19\x67\x64\x00\x20", 12); int8_t frame_type = 1; // keyframe @@ -910,7 +910,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); // Should produce enhanced FLV packet with 5-byte header + video data EXPECT_TRUE(flv_data != NULL); @@ -936,7 +936,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) } } - // Test mux_avc2flv_enhanced with coded frames + // Test mux_hevc2flv_enhanced with coded frames if (true) { std::string video_data = std::string("\x00\x00\x00\x0e\x26\x01\xaf\x06\xb8\x63\xef\x3a\x7f\x3c\x00\x01\x00\x80", 18); int8_t frame_type = 1; // keyframe @@ -946,7 +946,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); EXPECT_EQ(5 + video_data.length(), nb_flv); @@ -960,7 +960,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) } } - // Test mux_avc2flv_enhanced with inter frame + // Test mux_hevc2flv_enhanced with inter frame if (true) { std::string video_data = std::string("\x00\x00\x00\x08\x02\x01\xd0\x80\x93\x25\x88\x84", 12); int8_t frame_type = 2; // inter frame @@ -970,7 +970,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); if (flv_data) { @@ -982,7 +982,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) } } - // Test mux_avc2flv_enhanced with sequence end packet + // Test mux_hevc2flv_enhanced with sequence end packet if (true) { std::string video_data; // Empty for sequence end int8_t frame_type = 1; // keyframe @@ -992,7 +992,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); EXPECT_EQ(5, nb_flv); // Should produce 5-byte header only @@ -1014,7 +1014,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) } } - // Test mux_avc2flv_enhanced with different frame types + // Test mux_hevc2flv_enhanced with different frame types if (true) { std::string video_data = std::string("\x00\x00\x00\x06\x04\x01\x70\x80\x12\x34", 10); int8_t frame_type = 3; // disposable inter frame @@ -1024,7 +1024,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv_enhanced(video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); EXPECT_TRUE(flv_data != NULL); if (flv_data) { @@ -1036,7 +1036,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) } } - // Test mux_avc2flv_enhanced with empty video data + // Test mux_hevc2flv_enhanced with empty video data if (true) { std::string empty_video_data; int8_t frame_type = 1; // keyframe @@ -1046,7 +1046,7 @@ VOID TEST(ProtocolRawAvcTest, SrsRawHEVCStreamMuxAvc2flvEnhanced) char *flv_data = NULL; int nb_flv = 0; - HELPER_EXPECT_SUCCESS(hevc.mux_avc2flv_enhanced(empty_video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); + HELPER_EXPECT_SUCCESS(hevc.mux_hevc2flv_enhanced(empty_video_data, frame_type, packet_type, dts, pts, &flv_data, &nb_flv)); // Should produce enhanced FLV packet with 5-byte header only EXPECT_TRUE(flv_data != NULL);