/* * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). * * Use of this source code is governed by MIT-like license that can be found in the * LICENSE file in the root of the source tree. All contributing project authors * may be found in the AUTHORS file in the root of the source tree. */ #ifndef __rtmp_h #define __rtmp_h #include #include #include #include "amf.h" #include "Network/Buffer.h" #include "Extension/Track.h" #define DEFAULT_CHUNK_LEN 128 #define HANDSHAKE_PLAINTEXT 0x03 #define RANDOM_LEN (1536 - 8) #define MSG_SET_CHUNK 1 /*Set Chunk Size (1)*/ #define MSG_ABORT 2 /*Abort Message (2)*/ #define MSG_ACK 3 /*Acknowledgement (3)*/ #define MSG_USER_CONTROL 4 /*User Control Messages (4)*/ #define MSG_WIN_SIZE 5 /*Window Acknowledgement Size (5)*/ #define MSG_SET_PEER_BW 6 /*Set Peer Bandwidth (6)*/ #define MSG_AUDIO 8 /*Audio Message (8)*/ #define MSG_VIDEO 9 /*Video Message (9)*/ #define MSG_DATA 18 /*Data Message (18, 15) AMF0*/ #define MSG_DATA3 15 /*Data Message (18, 15) AMF3*/ #define MSG_CMD 20 /*Command Message AMF0 */ #define MSG_CMD3 17 /*Command Message AMF3 */ #define MSG_OBJECT3 16 /*Shared Object Message (19, 16) AMF3*/ #define MSG_OBJECT 19 /*Shared Object Message (19, 16) AMF0*/ #define MSG_AGGREGATE 22 /*Aggregate Message (22)*/ #define CONTROL_STREAM_BEGIN 0 #define CONTROL_STREAM_EOF 1 #define CONTROL_STREAM_DRY 2 #define CONTROL_SETBUFFER 3 #define CONTROL_STREAM_ISRECORDED 4 #define CONTROL_PING_REQUEST 6 #define CONTROL_PING_RESPONSE 7 #define STREAM_CONTROL 0 #define STREAM_MEDIA 1 #define CHUNK_NETWORK 2 /*网络相关的消息(参见 Protocol Control Messages)*/ #define CHUNK_SYSTEM 3 /*向服务器发送控制消息(反之亦可)*/ #define CHUNK_CLIENT_REQUEST_BEFORE 3 /*客户端在createStream前,向服务器发出请求的chunkID*/ #define CHUNK_CLIENT_REQUEST_AFTER 4 /*客户端在createStream后,向服务器发出请求的chunkID*/ #define CHUNK_AUDIO 6 /*音频chunkID*/ #define CHUNK_VIDEO 7 /*视频chunkID*/ namespace mediakit { #pragma pack(push, 1) class RtmpHandshake { public: RtmpHandshake(uint32_t _time, uint8_t *_random = nullptr); uint8_t time_stamp[4]; uint8_t zero[4] = {0}; uint8_t random[RANDOM_LEN]; void random_generate(char *bytes, int size); void create_complex_c0c1(); }; class RtmpHeader { public: #if __BYTE_ORDER == __BIG_ENDIAN uint8_t fmt : 2; uint8_t chunk_id : 6; #else uint8_t chunk_id : 6; // 0、1、2、3分别对应 12、8、4、1长度 [AUTO-TRANSLATED:31d67e40] // 0, 1, 2, 3 correspond to lengths of 12, 8, 4, 1 respectively uint8_t fmt : 2; #endif uint8_t time_stamp[3]; uint8_t body_size[3]; uint8_t type_id; uint8_t stream_index[4]; /* Note, this is little-endian while others are BE */ }; class FLVHeader { public: static constexpr uint8_t kFlvVersion = 1; static constexpr uint8_t kFlvHeaderLength = 9; //FLV char flv[3]; //File version (for example, 0x01 for FLV version 1) uint8_t version; #if __BYTE_ORDER == __BIG_ENDIAN // 保留,置0 [AUTO-TRANSLATED:46985374] // Preserve, set to 0 uint8_t : 5; // 是否有音频 [AUTO-TRANSLATED:9467870a] // Whether there is audio uint8_t have_audio: 1; // 保留,置0 [AUTO-TRANSLATED:46985374] // Preserve, set to 0 uint8_t : 1; // 是否有视频 [AUTO-TRANSLATED:42d0ed81] // Whether there is video uint8_t have_video: 1; #else // 是否有视频 [AUTO-TRANSLATED:42d0ed81] // Whether there is video uint8_t have_video: 1; // 保留,置0 [AUTO-TRANSLATED:46985374] // Preserve, set to 0 uint8_t : 1; // 是否有音频 [AUTO-TRANSLATED:9467870a] // Whether there is audio uint8_t have_audio: 1; // 保留,置0 [AUTO-TRANSLATED:46985374] // Preserve, set to 0 uint8_t : 5; #endif // The length of this header in bytes,固定为9 [AUTO-TRANSLATED:126988fc] // The length of this header in bytes, fixed to 9 uint32_t length; // 固定为0 [AUTO-TRANSLATED:d266c0a7] // Fixed to 0 uint32_t previous_tag_size0; }; class RtmpTagHeader { public: uint8_t type = 0; uint8_t data_size[3] = {0}; uint8_t timestamp[3] = {0}; uint8_t timestamp_ex = 0; uint8_t streamid[3] = {0}; /* Always 0. */ }; struct RtmpVideoHeaderEnhanced { #if __BYTE_ORDER == __BIG_ENDIAN uint8_t enhanced : 1; uint8_t frame_type : 3; uint8_t pkt_type : 4; uint32_t fourcc; #else uint8_t pkt_type : 4; uint8_t frame_type : 3; uint8_t enhanced : 1; uint32_t fourcc; #endif }; struct RtmpVideoHeaderClassic { #if __BYTE_ORDER == __BIG_ENDIAN uint8_t frame_type : 4; uint8_t codec_id : 4; uint8_t h264_pkt_type; #else uint8_t codec_id : 4; uint8_t frame_type : 4; uint8_t h264_pkt_type; #endif }; #pragma pack(pop) class RtmpPacket : public toolkit::Buffer{ public: friend class RtmpProtocol; using Ptr = std::shared_ptr; bool is_abs_stamp; uint8_t type_id; uint32_t time_stamp; uint32_t ts_field; uint32_t stream_index; uint32_t chunk_id; size_t body_size; toolkit::BufferLikeString buffer; public: static Ptr create(); char *data() const override{ return (char*)buffer.data(); } size_t size() const override { return buffer.size(); } void clear(); // video config frame和key frame都返回true [AUTO-TRANSLATED:de025c52] // video config frame and key frame both return true // 用于gop缓存定位 [AUTO-TRANSLATED:828204e5] // Used for gop cache positioning bool isVideoKeyFrame() const; // aac config或h264/h265 config返回true,支持增强型rtmp [AUTO-TRANSLATED:221955ec] // aac config or h264/h265 config returns true, supports enhanced rtmp // 用于缓存解码配置信息 [AUTO-TRANSLATED:19304f64] // Used to cache decoding configuration information bool isConfigFrame() const; int getRtmpCodecId() const; int getAudioSampleRate() const; int getAudioSampleBit() const; int getAudioChannel() const; private: friend class toolkit::ResourcePool_l; RtmpPacket(){ clear(); } RtmpPacket &operator=(const RtmpPacket &that); private: // 对象个数统计 [AUTO-TRANSLATED:3b43e8c2] // Object count statistics toolkit::ObjectStatistic _statistic; }; /** * rtmp metadata基类,用于描述rtmp格式信息 * rtmp metadata base class, used to describe rtmp format information * [AUTO-TRANSLATED:8ced489c] */ class Metadata { public: using Ptr = std::shared_ptr; Metadata(): _metadata(AMF_OBJECT) {} const AMFValue &getMetadata() const{ return _metadata; } static void addTrack(AMFValue &metadata, const Track::Ptr &track); protected: AMFValue _metadata; }; /** * metadata中除音视频外的其他描述部分 * Other descriptive parts in metadata besides audio and video * [AUTO-TRANSLATED:e11f031f] */ class TitleMeta : public Metadata { public: using Ptr = std::shared_ptr; TitleMeta(float dur_sec = 0, size_t fileSize = 0, const std::map &header = std::map()); }; class VideoMeta : public Metadata { public: using Ptr = std::shared_ptr; VideoMeta(const VideoTrack::Ptr &video); }; class AudioMeta : public Metadata { public: using Ptr = std::shared_ptr; AudioMeta(const AudioTrack::Ptr &audio); }; // 根据音频track获取flags [AUTO-TRANSLATED:a25fdd07] // Get flags based on audio track uint8_t getAudioRtmpFlags(const Track::Ptr &track); ////////////////// rtmp video ////////////////////////// //https://rtmp.veriskope.com/pdf/video_file_format_spec_v10_1.pdf // UB [4]; Type of video frame. enum class RtmpFrameType : uint8_t { reserved = 0, key_frame = 1, // key frame (for AVC, a seekable frame) inter_frame = 2, // inter frame (for AVC, a non-seekable frame) disposable_inter_frame = 3, // disposable inter frame (H.263 only) generated_key_frame = 4, // generated key frame (reserved for server use only) video_info_frame = 5, // video info/command frame }; #define MKBETAG(a, b, c, d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) // UB [4]; Codec Identifier. enum class RtmpVideoCodec : uint32_t { h263 = 2, // Sorenson H.263 screen_video = 3, // Screen video vp6 = 4, // On2 VP6 vp6_alpha = 5, // On2 VP6 with alpha channel screen_video2 = 6, // Screen video version 2 h264 = 7, // avc h265 = 12, // 国内扩展 // 增强型rtmp FourCC [AUTO-TRANSLATED:442b77fb] // Enhanced rtmp FourCC fourcc_vp9 = MKBETAG('v', 'p', '0', '9'), fourcc_av1 = MKBETAG('a', 'v', '0', '1'), fourcc_hevc = MKBETAG('h', 'v', 'c', '1') }; // UI8; enum class RtmpH264PacketType : uint8_t { h264_config_header = 0, // AVC or HEVC sequence header(sps/pps) h264_nalu = 1, // AVC or HEVC NALU h264_end_seq = 2, // AVC or HEVC end of sequence (lower level NALU sequence ender is not REQUIRED or supported) }; // https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf // UB[4] enum class RtmpPacketType : uint8_t { PacketTypeSequenceStart = 0, PacketTypeCodedFrames = 1, PacketTypeSequenceEnd = 2, // CompositionTime Offset is implied to equal zero. This is // an optimization to save putting SI24 composition time value of zero on // the wire. See pseudo code below in the VideoTagBody section PacketTypeCodedFramesX = 3, // VideoTagBody does not contain video data. VideoTagBody // instead contains an AMF encoded metadata. See Metadata Frame // section for an illustration of its usage. As an example, the metadata // can be HDR information. This is a good way to signal HDR // information. This also opens up future ways to express additional // metadata that is meant for the next video sequence. // // note: presence of PacketTypeMetadata means that FrameType // flags at the top of this table should be ignored PacketTypeMetadata = 4, // Carriage of bitstream in MPEG-2 TS format // note: PacketTypeSequenceStart and PacketTypeMPEG2TSSequenceStart // are mutually exclusive PacketTypeMPEG2TSSequenceStart = 5, }; ////////////////// rtmp audio ////////////////////////// //https://rtmp.veriskope.com/pdf/video_file_format_spec_v10_1.pdf // UB [4]; Format of SoundData enum class RtmpAudioCodec : uint8_t { /** 0 = Linear PCM, platform endian 1 = ADPCM 2 = MP3 3 = Linear PCM, little endian 4 = Nellymoser 16 kHz mono 5 = Nellymoser 8 kHz mono 6 = Nellymoser 7 = G.711 A-law logarithmic PCM 8 = G.711 mu-law logarithmic PCM 9 = reserved 10 = AAC 11 = Speex 14 = MP3 8 kHz 15 = Device-specific sound */ g711a = 7, g711u = 8, aac = 10, opus = 13 // 国内扩展 }; // UI8; enum class RtmpAACPacketType : uint8_t { aac_config_header = 0, // AAC sequence header aac_raw = 1, // AAC raw }; //////////////////////////////////////////// struct RtmpPacketInfo { enum { kEnhancedRtmpHeaderSize = sizeof(RtmpVideoHeaderEnhanced) }; CodecId codec = CodecInvalid; bool is_enhanced; union { struct { RtmpFrameType frame_type; RtmpPacketType pkt_type; // enhanced = true RtmpH264PacketType h264_pkt_type; // enhanced = false } video; }; }; // https://github.com/veovera/enhanced-rtmp CodecId parseVideoRtmpPacket(const uint8_t *data, size_t size, RtmpPacketInfo *info = nullptr); }//namespace mediakit #endif//__rtmp_h