diff --git a/README.md b/README.md index f4b65c3e..f932273b 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ - [谁在使用zlmediakit?](https://github.com/ZLMediaKit/ZLMediaKit/issues/511) - 全面支持ipv6网络 - 支持多轨道模式(一个流中多个视频/音频) +- 全协议支持H264/H265/AAC/G711/OPUS,部分支持VP8/VP9/AV1/JPEG/MP3/H266/ADPCM/SVAC/G722/G723/G729 ## 项目定位 diff --git a/ext-codec/AAC.cpp b/ext-codec/AAC.cpp index 614ec979..b6cc8a61 100644 --- a/ext-codec/AAC.cpp +++ b/ext-codec/AAC.cpp @@ -373,10 +373,6 @@ Track::Ptr AACTrack::clone() const { } Sdp::Ptr AACTrack::getSdp(uint8_t payload_type) const { - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } return std::make_shared(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10); } diff --git a/ext-codec/G711.cpp b/ext-codec/G711.cpp index dae2260f..0ea6c762 100644 --- a/ext-codec/G711.cpp +++ b/ext-codec/G711.cpp @@ -19,70 +19,14 @@ using namespace toolkit; namespace mediakit { -/** - * G711类型SDP - * G711 type SDP - - * [AUTO-TRANSLATED:ea72d60a] - */ -class G711Sdp : public Sdp { -public: - /** - * G711采样率固定为8000 - * @param codecId G711A G711U - * @param payload_type rtp payload type - * @param sample_rate 音频采样率 - * @param channels 通道数 - * @param bitrate 比特率 - * G711 sampling rate is fixed at 8000 - * @param codecId G711A G711U - * @param payload_type rtp payload type - * @param sample_rate audio sampling rate - * @param channels number of channels - * @param bitrate bitrate - - * [AUTO-TRANSLATED:5ea4b771] - */ - G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate) - : Sdp(sample_rate, payload_type) { - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " " << getCodecName(codecId) << "/" << sample_rate << "/" << channels << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - -private: - _StrPrinter _printer; -}; - Track::Ptr G711Track::clone() const { return std::make_shared(*this); } Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const { - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } - - const auto codec = getCodecId(); - const auto sample_rate = getAudioSampleRate(); - const auto audio_channel = getAudioChannel(); - const auto bitrate = getBitRate() >> 10; - if (sample_rate == 8000 && audio_channel == 1) { - // https://datatracker.ietf.org/doc/html/rfc3551#section-6 - payload_type = (codec == CodecG711U) ? Rtsp::PT_PCMU : Rtsp::PT_PCMA; - } - - return std::make_shared(codec, payload_type, sample_rate, audio_channel, bitrate); + return std::make_shared(payload_type, *this); } - namespace { CodecId getCodecA() { diff --git a/ext-codec/H264.cpp b/ext-codec/H264.cpp index 984e2111..50dcfb22 100644 --- a/ext-codec/H264.cpp +++ b/ext-codec/H264.cpp @@ -357,10 +357,6 @@ private: }; Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const { - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } return std::make_shared(_sps, _pps, payload_type, getBitRate() >> 10); } diff --git a/ext-codec/H265.cpp b/ext-codec/H265.cpp index ff2a1b92..0d0299b3 100644 --- a/ext-codec/H265.cpp +++ b/ext-codec/H265.cpp @@ -263,10 +263,6 @@ private: }; Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const { - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } return std::make_shared(_vps, _sps, _pps, payload_type, getBitRate() >> 10); } diff --git a/ext-codec/JPEG.cpp b/ext-codec/JPEG.cpp index d265f0b1..40f7c0ae 100644 --- a/ext-codec/JPEG.cpp +++ b/ext-codec/JPEG.cpp @@ -31,26 +31,10 @@ void JPEGTrack::getVideoResolution(const uint8_t *buf, int len) { } } -class JPEGSdp : public Sdp { -public: - JPEGSdp(int bitrate) : Sdp(90000, Rtsp::PT_JPEG) { - _printer << "m=video 0 RTP/AVP " << (int)getPayloadType() << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - } - - std::string getSdp() const { return _printer; } - -private: - _StrPrinter _printer; -}; - -Sdp::Ptr JPEGTrack::getSdp(uint8_t) const { - return std::make_shared(getBitRate() >> 10); +Sdp::Ptr JPEGTrack::getSdp(uint8_t pt) const { + return std::make_shared(pt, *this); } - namespace { CodecId getCodec() { diff --git a/ext-codec/L16.cpp b/ext-codec/L16.cpp index e91d9043..5ad5c948 100644 --- a/ext-codec/L16.cpp +++ b/ext-codec/L16.cpp @@ -18,50 +18,8 @@ using namespace toolkit; namespace mediakit { -/** - * L16类型SDP - * L16 type SDP - - * [AUTO-TRANSLATED:11b1196d] - */ -class L16Sdp : public Sdp { -public: - /** - * L16采样位数固定为16位 - * @param payload_type rtp payload type - * @param channels 通道数 - * @param sample_rate 音频采样率 - * @param bitrate 比特率 - * L16 sampling bit width is fixed to 16 bits - * @param payload_type rtp payload type - * @param channels number of channels - * @param sample_rate audio sampling rate - * @param bitrate bitrate - - - * [AUTO-TRANSLATED:7a08a400] - */ - L16Sdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) { - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecL16) << "/" << sample_rate << "/" << channels << "\r\n"; - } - - string getSdp() const override { return _printer; } - -private: - _StrPrinter _printer; -}; - Sdp::Ptr L16Track::getSdp(uint8_t payload_type) const { - WarnL << "Enter L16Track::getSdp function"; - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } - return std::make_shared(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10); + return std::make_shared(payload_type, *this); } Track::Ptr L16Track::clone() const { diff --git a/ext-codec/Opus.cpp b/ext-codec/Opus.cpp index 2f227813..4ec57879 100644 --- a/ext-codec/Opus.cpp +++ b/ext-codec/Opus.cpp @@ -18,51 +18,9 @@ using namespace toolkit; namespace mediakit { -/** - * Opus类型SDP - * Opus type SDP - - * [AUTO-TRANSLATED:6c0a72ed] - */ -class OpusSdp : public Sdp { -public: - /** - * 构造opus sdp - * @param payload_type rtp payload type - * @param sample_rate 音频采样率 - * @param channels 通道数 - * @param bitrate 比特率 - * Construct opus sdp - * @param payload_type rtp payload type - * @param sample_rate audio sample rate - * @param channels number of channels - * @param bitrate bitrate - - - * [AUTO-TRANSLATED:40713e9d] - */ - OpusSdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) { - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " " << getCodecName(CodecOpus) << "/" << sample_rate << "/" << channels << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - -private: - _StrPrinter _printer; -}; Sdp::Ptr OpusTrack::getSdp(uint8_t payload_type) const { - if (!ready()) { - WarnL << getCodecName() << " Track未准备好"; - return nullptr; - } - return std::make_shared(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10); + return std::make_shared(payload_type, *this); } namespace { diff --git a/src/Extension/Factory.cpp b/src/Extension/Factory.cpp index f4309675..57d67132 100644 --- a/src/Extension/Factory.cpp +++ b/src/Extension/Factory.cpp @@ -10,6 +10,8 @@ #include "Factory.h" #include "Rtmp/Rtmp.h" +#include "CommonRtmp.h" +#include "CommonRtp.h" #include "Common/config.h" using namespace std; @@ -19,15 +21,6 @@ namespace mediakit { static std::unordered_map s_plugins; -extern CodecPlugin h264_plugin; -extern CodecPlugin h265_plugin; -extern CodecPlugin jpeg_plugin; -extern CodecPlugin aac_plugin; -extern CodecPlugin opus_plugin; -extern CodecPlugin g711a_plugin; -extern CodecPlugin g711u_plugin; -extern CodecPlugin l16_plugin; - REGISTER_CODEC(h264_plugin); REGISTER_CODEC(h265_plugin); REGISTER_CODEC(jpeg_plugin); @@ -51,8 +44,7 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) { } auto it = s_plugins.find(codec); if (it == s_plugins.end()) { - WarnL << "Unsupported codec: " << track->getName(); - return nullptr; + return getTrackByCodecId(codec, track->_samplerate, track->_channel); } return it->second->getTrackBySdp(track); } @@ -69,8 +61,8 @@ Track::Ptr Factory::getTrackByAbstractTrack(const Track::Ptr &track) { RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec, uint8_t pt) { auto it = s_plugins.find(codec); if (it == s_plugins.end()) { - WarnL << "Unsupported codec: " << getCodecName(codec); - return nullptr; + WarnL << "Unsupported codec: " << getCodecName(codec) << ", use CommonRtpEncoder"; + return std::make_shared(); } return it->second->getRtpEncoderByCodecId(pt); } @@ -78,8 +70,8 @@ RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec, uint8_t pt) { RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) { auto it = s_plugins.find(codec); if (it == s_plugins.end()) { - WarnL << "Unsupported codec: " << getCodecName(codec); - return nullptr; + WarnL << "Unsupported codec: " << getCodecName(codec) << ", use CommonRtpDecoder"; + return std::make_shared(codec, 10 * 1024); } return it->second->getRtpDecoderByCodecId(); } @@ -87,7 +79,7 @@ RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) { // ///////////////////////////rtmp相关/////////////////////////////////////////// [AUTO-TRANSLATED:da9645df] // ///////////////////////////rtmp related/////////////////////////////////////////// -static CodecId getVideoCodecIdByAmf(const AMFValue &val){ +static CodecId getVideoCodecIdByAmf(const AMFValue &val) { if (val.type() == AMF_STRING) { auto str = val.as_string(); if (str == "avc1") { @@ -117,15 +109,25 @@ static CodecId getVideoCodecIdByAmf(const AMFValue &val){ Track::Ptr Factory::getTrackByCodecId(CodecId codec, int sample_rate, int channels, int sample_bit) { auto it = s_plugins.find(codec); if (it == s_plugins.end()) { - WarnL << "Unsupported codec: " << getCodecName(codec); - return nullptr; + auto type = mediakit::getTrackType(codec); + switch (type) { + case TrackAudio: { + WarnL << "Unsupported codec: " << getCodecName(codec) << ", use default audio track"; + return std::make_shared(codec, sample_rate, channels, sample_bit); + } + case TrackVideo: { + WarnL << "Unsupported codec: " << getCodecName(codec) << ", use default video track"; + return std::make_shared(codec, 0, 0, 0); + } + default: WarnL << "Unsupported codec: " << getCodecName(codec); return nullptr; + } } return it->second->getTrackByCodecId(sample_rate, channels, sample_bit); } Track::Ptr Factory::getVideoTrackByAmf(const AMFValue &amf) { CodecId codecId = getVideoCodecIdByAmf(amf); - if(codecId == CodecInvalid){ + if (codecId == CodecInvalid) { return nullptr; } return getTrackByCodecId(codecId); @@ -144,18 +146,19 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) { if (val.type() != AMF_NULL) { auto type_id = (RtmpAudioCodec)val.as_integer(); switch (type_id) { - case RtmpAudioCodec::aac : return CodecAAC; - case RtmpAudioCodec::g711a : return CodecG711A; - case RtmpAudioCodec::g711u : return CodecG711U; - case RtmpAudioCodec::opus : return CodecOpus; - default : WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid; + case RtmpAudioCodec::aac: return CodecAAC; + case RtmpAudioCodec::mp3: return CodecMP3; + case RtmpAudioCodec::adpcm: return CodecADPCM; + case RtmpAudioCodec::g711a: return CodecG711A; + case RtmpAudioCodec::g711u: return CodecG711U; + case RtmpAudioCodec::opus: return CodecOpus; + default: WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid; } } - return CodecInvalid; } -Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int channels, int sample_bit){ +Track::Ptr Factory::getAudioTrackByAmf(const AMFValue &amf, int sample_rate, int channels, int sample_bit) { CodecId codecId = getAudioCodecIdByAmf(amf); if (codecId == CodecInvalid) { return nullptr; @@ -166,8 +169,8 @@ Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int RtmpCodec::Ptr Factory::getRtmpDecoderByTrack(const Track::Ptr &track) { auto it = s_plugins.find(track->getCodecId()); if (it == s_plugins.end()) { - WarnL << "Unsupported codec: " << track->getCodecName(); - return nullptr; + WarnL << "Unsupported codec: " << track->getCodecName() << ", use CommonRtmpDecoder"; + return std::make_shared(track); } return it->second->getRtmpDecoderByTrack(track); } @@ -175,8 +178,8 @@ RtmpCodec::Ptr Factory::getRtmpDecoderByTrack(const Track::Ptr &track) { RtmpCodec::Ptr Factory::getRtmpEncoderByTrack(const Track::Ptr &track) { auto it = s_plugins.find(track->getCodecId()); if (it == s_plugins.end()) { - WarnL << "Unsupported codec: " << track->getCodecName(); - return nullptr; + WarnL << "Unsupported codec: " << track->getCodecName() << ", use CommonRtmpEncoder"; + return std::make_shared(track); } return it->second->getRtmpEncoderByTrack(track); } @@ -190,6 +193,8 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) { case CodecG711A: return AMFValue((int)RtmpAudioCodec::g711a); case CodecG711U: return AMFValue((int)RtmpAudioCodec::g711u); case CodecOpus: return AMFValue((int)RtmpAudioCodec::opus); + case CodecADPCM: return AMFValue((int)RtmpAudioCodec::adpcm); + case CodecMP3: return AMFValue((int)RtmpAudioCodec::mp3); case CodecAV1: return AMFValue((int)RtmpVideoCodec::fourcc_av1); case CodecVP9: return AMFValue((int)RtmpVideoCodec::fourcc_vp9); default: return AMFValue(AMF_NULL); @@ -208,11 +213,10 @@ Frame::Ptr Factory::getFrameFromPtr(CodecId codec, const char *data, size_t byte Frame::Ptr Factory::getFrameFromBuffer(CodecId codec, Buffer::Ptr data, uint64_t dts, uint64_t pts) { auto frame = Factory::getFrameFromPtr(codec, data->data(), data->size(), dts, pts); - if(!frame){ + if (!frame) { return nullptr; } return std::make_shared(frame, false, std::move(data)); } -}//namespace mediakit - +} // namespace mediakit diff --git a/src/Extension/Factory.h b/src/Extension/Factory.h index d7d3665c..7f7bdceb 100644 --- a/src/Extension/Factory.h +++ b/src/Extension/Factory.h @@ -23,6 +23,7 @@ #define REGISTER_STATIC_VAR(var_name, line) REGISTER_STATIC_VAR_INNER(var_name, line) #define REGISTER_CODEC(plugin) \ +extern CodecPlugin plugin; \ static toolkit::onceToken REGISTER_STATIC_VAR(s_token, __LINE__) ([]() { \ Factory::registerPlugin(plugin); \ }); diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 5bf66038..ca38b5a7 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -43,7 +43,18 @@ typedef enum { XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8, MOV_OBJECT_VP8) \ XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9, MOV_OBJECT_VP9) \ XX(CodecAV1, TrackVideo, 9, "AV1", PSI_STREAM_AV1, MOV_OBJECT_AV1) \ - XX(CodecJPEG, TrackVideo, 10, "JPEG", PSI_STREAM_JPEG_2000, MOV_OBJECT_JPEG) + XX(CodecJPEG, TrackVideo, 10, "JPEG", PSI_STREAM_JPEG_2000, MOV_OBJECT_JPEG) \ + XX(CodecH266, TrackVideo, 11, "H266", PSI_STREAM_H266, MOV_OBJECT_H266) \ + XX(CodecTS, TrackVideo, 12, "MP2T", PSI_STREAM_RESERVED, MOV_OBJECT_NONE) \ + XX(CodecPS, TrackVideo, 13, "MPEG", PSI_STREAM_RESERVED, MOV_OBJECT_NONE) \ + XX(CodecMP3, TrackAudio, 14, "MP3", PSI_STREAM_MP3, MOV_OBJECT_MP3) \ + XX(CodecADPCM, TrackAudio, 15, "ADPCM", PSI_STREAM_RESERVED, MOV_OBJECT_NONE) \ + XX(CodecSVACV, TrackVideo, 16, "SVACV", PSI_STREAM_VIDEO_SVAC, MOV_OBJECT_NONE) \ + XX(CodecSVACA, TrackAudio, 17, "SVACA", PSI_STREAM_AUDIO_SVAC, MOV_OBJECT_NONE) \ + XX(CodecG722, TrackAudio, 18, "G722", PSI_STREAM_AUDIO_G722, MOV_OBJECT_NONE) \ + XX(CodecG723, TrackAudio, 19, "G723", PSI_STREAM_AUDIO_G723, MOV_OBJECT_NONE) \ + XX(CodecG728, TrackAudio, 20, "G728", PSI_STREAM_RESERVED, MOV_OBJECT_NONE) \ + XX(CodecG729, TrackAudio, 21, "G729", PSI_STREAM_AUDIO_G729, MOV_OBJECT_NONE) typedef enum { CodecInvalid = -1, diff --git a/src/Extension/Track.cpp b/src/Extension/Track.cpp new file mode 100644 index 00000000..4e9e424c --- /dev/null +++ b/src/Extension/Track.cpp @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#include "Track.h" +#include "Util/util.h" + +using namespace std; +using namespace toolkit; + +namespace mediakit { + +Sdp::Ptr AudioTrackImp::getSdp(uint8_t payload_type) const { + return std::make_shared(payload_type, *this); +} +Sdp::Ptr VideoTrackImp::getSdp(uint8_t payload_type) const { + return std::make_shared(payload_type, *this); +} + +} // namespace mediakit \ No newline at end of file diff --git a/src/Extension/Track.h b/src/Extension/Track.h index 6c5712b2..212bd7fc 100644 --- a/src/Extension/Track.h +++ b/src/Extension/Track.h @@ -201,7 +201,7 @@ public: bool ready() const override { return true; } Track::Ptr clone() const override { return std::make_shared(*this); } - Sdp::Ptr getSdp(uint8_t payload_type) const override { return nullptr; } + Sdp::Ptr getSdp(uint8_t payload_type) const override; CodecId getCodecId() const override { return _codec_id; } private: @@ -298,7 +298,7 @@ public: * [AUTO-TRANSLATED:9af5a0a4] */ int getAudioSampleRate() const override{ - return _sample_rate; + return _sample_rate ? _sample_rate : RtpPayload::getClockRateByCodec(_codecid); } /** @@ -308,7 +308,7 @@ public: * [AUTO-TRANSLATED:5fedc65d] */ int getAudioSampleBit() const override{ - return _sample_bit; + return _sample_bit ? _sample_bit : 16; } /** @@ -318,11 +318,11 @@ public: * [AUTO-TRANSLATED:2613b317] */ int getAudioChannel() const override{ - return _channels; + return _channels ? _channels : 1; } Track::Ptr clone() const override { return std::make_shared(*this); } - Sdp::Ptr getSdp(uint8_t payload_type) const override { return nullptr; } + Sdp::Ptr getSdp(uint8_t payload_type) const override; private: CodecId _codecid; diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index 9b6ae466..76a9da99 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -68,29 +68,23 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track) { auto iChannel = audioTrack->getAudioChannel(); auto iSampleBit = audioTrack->getAudioSampleBit(); - uint8_t flvAudioType; + auto amf = Factory::getAmfByCodecId(track->getCodecId()); + if (!amf) { + WarnL << "该编码格式不支持转换为RTMP: " << track->getCodecName(); + return 0; + } + uint8_t flvAudioType = amf.as_integer(); switch (track->getCodecId()) { - case CodecG711A: flvAudioType = (uint8_t)RtmpAudioCodec::g711a; break; - case CodecG711U: flvAudioType = (uint8_t)RtmpAudioCodec::g711u; break; + case CodecAAC: case CodecOpus: { - flvAudioType = (uint8_t)RtmpAudioCodec::opus; - // opus不通过flags获取音频相关信息 [AUTO-TRANSLATED:0ddf328b] - // opus does not get audio information through flags + // opus/aac不通过flags获取音频相关信息 [AUTO-TRANSLATED:0ddf328b] + // opus/aac does not get audio information through flags iSampleRate = 44100; iSampleBit = 16; iChannel = 2; break; } - case CodecAAC: { - flvAudioType = (uint8_t)RtmpAudioCodec::aac; - // aac不通过flags获取音频相关信息 [AUTO-TRANSLATED:63ac5081] - // aac does not get audio information through flags - iSampleRate = 44100; - iSampleBit = 16; - iChannel = 2; - break; - } - default: WarnL << "该编码格式不支持转换为RTMP: " << track->getCodecName(); return 0; + default: break; } uint8_t flvSampleRate; diff --git a/src/Rtmp/Rtmp.h b/src/Rtmp/Rtmp.h index fd02da7c..9b1c135a 100644 --- a/src/Rtmp/Rtmp.h +++ b/src/Rtmp/Rtmp.h @@ -371,6 +371,8 @@ enum class RtmpAudioCodec : uint8_t { 14 = MP3 8 kHz 15 = Device-specific sound */ + adpcm = 1, + mp3 = 2, g711a = 7, g711u = 8, aac = 10, diff --git a/src/Rtp/Decoder.cpp b/src/Rtp/Decoder.cpp index 5a148703..54d213dd 100644 --- a/src/Rtp/Decoder.cpp +++ b/src/Rtp/Decoder.cpp @@ -90,7 +90,8 @@ void DecoderImp::onStream(int stream, int codecid, const void *extra, size_t byt } // G711传统只支持 8000/1/16的规格,FFmpeg貌似做了扩展,但是这里不管它了 [AUTO-TRANSLATED:851813f7] // G711 traditionally only supports the 8000/1/16 specification. FFmpeg seems to have extended it, but we'll ignore that here. - auto track = Factory::getTrackByCodecId(getCodecByMpegId(codecid), 8000, 1, 16); + auto codec = getCodecByMpegId(codecid); + auto track= Factory::getTrackByCodecId(codec); if (track) { onTrack(stream, std::move(track)); } @@ -113,7 +114,7 @@ void DecoderImp::onDecode(int stream, int codecid, int flags, int64_t pts, int64 } auto &ref = _tracks[stream]; if (!ref.first) { - onTrack(stream, Factory::getTrackByCodecId(codec, 8000, 1, 16)); + onTrack(stream, Factory::getTrackByCodecId(codec)); } if (!ref.first) { WarnL << "Unsupported codec :" << getCodecName(codec); diff --git a/src/Rtsp/Rtsp.cpp b/src/Rtsp/Rtsp.cpp index 19d8da5d..27c7eb6f 100644 --- a/src/Rtsp/Rtsp.cpp +++ b/src/Rtsp/Rtsp.cpp @@ -12,9 +12,10 @@ #include #include #include "Rtsp.h" +#include "Network/Socket.h" #include "Common/Parser.h" #include "Common/config.h" -#include "Network/Socket.h" +#include "Extension/Track.h" #include "Extension/Factory.h" using namespace std; @@ -24,50 +25,84 @@ namespace mediakit { int RtpPayload::getClockRate(int pt) { switch (pt) { -#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) \ +#define XX(name, type, value, clock_rate, channel, codec_id) \ case value: return clock_rate; - RTP_PT_MAP(SWITCH_CASE) -#undef SWITCH_CASE + RTP_PT_MAP(XX) +#undef XX default: return 90000; } } +int RtpPayload::getClockRateByCodec(CodecId codec) { +#define XX(name, type, value, clock_rate, channel, codec_id) { codec_id, clock_rate }, + static map s_map = { RTP_PT_MAP(XX) }; +#undef XX + auto it = s_map.find(codec); + if (it == s_map.end()) { + WarnL << "Unsupported codec: " << getCodecName(codec); + return 90000; + } + return it->second; +} + +int RtpPayload::getPayloadType(const Track &track) { +#define XX(name, type, value, clock_rate, channel, codec_id) { codec_id, info { clock_rate, channel, value } }, + struct info { + int clock_rate; + int channels; + int pt; + }; + static map s_map = { RTP_PT_MAP(XX) }; +#undef XX + auto it = s_map.find(track.getCodecId()); + if (it == s_map.end()) { + return -1; + } + if (track.getTrackType() == TrackAudio) { + if (static_cast(track).getAudioSampleRate() != it->second.clock_rate + || static_cast(track).getAudioChannel() != it->second.channels) { + return -1; + } + } + return it->second.pt; +} + TrackType RtpPayload::getTrackType(int pt) { switch (pt) { -#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) \ +#define XX(name, type, value, clock_rate, channel, codec_id) \ case value: return type; - RTP_PT_MAP(SWITCH_CASE) -#undef SWITCH_CASE + RTP_PT_MAP(XX) +#undef XX default: return TrackInvalid; } } int RtpPayload::getAudioChannel(int pt) { switch (pt) { -#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) \ +#define XX(name, type, value, clock_rate, channel, codec_id) \ case value: return channel; - RTP_PT_MAP(SWITCH_CASE) -#undef SWITCH_CASE + RTP_PT_MAP(XX) +#undef XX default: return 1; } } const char *RtpPayload::getName(int pt) { switch (pt) { -#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) \ +#define XX(name, type, value, clock_rate, channel, codec_id) \ case value: return #name; - RTP_PT_MAP(SWITCH_CASE) -#undef SWITCH_CASE + RTP_PT_MAP(XX) +#undef XX default: return "unknown payload type"; } } CodecId RtpPayload::getCodecId(int pt) { switch (pt) { -#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) \ +#define XX(name, type, value, clock_rate, channel, codec_id) \ case value: return codec_id; - RTP_PT_MAP(SWITCH_CASE) -#undef SWITCH_CASE + RTP_PT_MAP(XX) +#undef XX default: return CodecInvalid; } } @@ -91,13 +126,7 @@ static void getAttrSdp(const multimap &attr, _StrPrinter &printe } string SdpTrack::getName() const { - switch (_pt) { -#define SWITCH_CASE(name, type, value, clock_rate, channel, codec_id) \ - case value: return #name; - RTP_PT_MAP(SWITCH_CASE) -#undef SWITCH_CASE - default: return _codec; - } + return RtpPayload::getName(_pt); } string SdpTrack::getControlUrl(const string &base_url) const { @@ -715,6 +744,23 @@ TitleSdp::TitleSdp(float dur_sec, const std::map &head _printer << "a=control:*\r\n"; } +DefaultSdp::DefaultSdp(int payload_type, const Track &track) + : Sdp(track.getTrackType() == TrackVideo ? 9000 : static_cast(track).getAudioSampleRate(), payload_type) { + _printer << "m=" << track.getTrackTypeStr() << " 0 RTP/AVP " << payload_type << "\r\n"; + auto bitrate = track.getBitRate() >> 10; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + if (payload_type < 96) { + return; + } + _printer << "a=rtpmap:" << payload_type << " " << track.getCodecName() << "/" << getSampleRate(); + if (track.getTrackType() == TrackAudio) { + _printer << "/" << static_cast(track).getAudioChannel(); + } + _printer << "\r\n"; +} + } // namespace mediakit namespace toolkit { diff --git a/src/Rtsp/Rtsp.h b/src/Rtsp/Rtsp.h index a46e4927..f94664c2 100644 --- a/src/Rtsp/Rtsp.h +++ b/src/Rtsp/Rtsp.h @@ -11,16 +11,18 @@ #ifndef RTSP_RTSP_H_ #define RTSP_RTSP_H_ -#include "Common/macros.h" -#include "Extension/Frame.h" -#include "Network/Socket.h" -#include #include #include +#include #include +#include "Network/Socket.h" +#include "Common/macros.h" +#include "Extension/Frame.h" namespace mediakit { +class Track; + namespace Rtsp { typedef enum { RTP_Invalid = -1, @@ -32,27 +34,27 @@ typedef enum { #define RTP_PT_MAP(XX) \ XX(PCMU, TrackAudio, 0, 8000, 1, CodecG711U) \ XX(GSM, TrackAudio, 3, 8000, 1, CodecInvalid) \ - XX(G723, TrackAudio, 4, 8000, 1, CodecInvalid) \ + XX(G723, TrackAudio, 4, 8000, 1, CodecG723) \ XX(DVI4_8000, TrackAudio, 5, 8000, 1, CodecInvalid) \ XX(DVI4_16000, TrackAudio, 6, 16000, 1, CodecInvalid) \ XX(LPC, TrackAudio, 7, 8000, 1, CodecInvalid) \ XX(PCMA, TrackAudio, 8, 8000, 1, CodecG711A) \ - XX(G722, TrackAudio, 9, 8000, 1, CodecInvalid) \ + XX(G722, TrackAudio, 9, 16000, 1, CodecG722) \ XX(L16_Stereo, TrackAudio, 10, 44100, 2, CodecInvalid) \ XX(L16_Mono, TrackAudio, 11, 44100, 1, CodecInvalid) \ XX(QCELP, TrackAudio, 12, 8000, 1, CodecInvalid) \ XX(CN, TrackAudio, 13, 8000, 1, CodecInvalid) \ - XX(MPA, TrackAudio, 14, 90000, 1, CodecInvalid) \ - XX(G728, TrackAudio, 15, 8000, 1, CodecInvalid) \ + XX(MP3, TrackAudio, 14, 44100, 2, CodecMP3) \ + XX(G728, TrackAudio, 15, 8000, 1, CodecG728) \ XX(DVI4_11025, TrackAudio, 16, 11025, 1, CodecInvalid) \ XX(DVI4_22050, TrackAudio, 17, 22050, 1, CodecInvalid) \ - XX(G729, TrackAudio, 18, 8000, 1, CodecInvalid) \ + XX(G729, TrackAudio, 18, 8000, 1, CodecG729) \ XX(CelB, TrackVideo, 25, 90000, 1, CodecInvalid) \ XX(JPEG, TrackVideo, 26, 90000, 1, CodecJPEG) \ XX(nv, TrackVideo, 28, 90000, 1, CodecInvalid) \ XX(H261, TrackVideo, 31, 90000, 1, CodecInvalid) \ XX(MPV, TrackVideo, 32, 90000, 1, CodecInvalid) \ - XX(MP2T, TrackVideo, 33, 90000, 1, CodecInvalid) \ + XX(MP2T, TrackVideo, 33, 90000, 1, CodecTS) \ XX(H263, TrackVideo, 34, 90000, 1, CodecInvalid) typedef enum { @@ -213,10 +215,12 @@ private: class RtpPayload { public: static int getClockRate(int pt); + static int getClockRateByCodec(CodecId codec); static TrackType getTrackType(int pt); static int getAudioChannel(int pt); static const char *getName(int pt); static CodecId getCodecId(int pt); + static int getPayloadType(const Track &track); private: RtpPayload() = delete; @@ -243,8 +247,8 @@ public: public: int _pt = 0xff; - int _channel; - int _samplerate; + int _channel = 0; + int _samplerate = 0; TrackType _type; std::string _codec; std::string _fmtp; @@ -340,6 +344,15 @@ private: uint32_t _sample_rate; }; +class DefaultSdp : public Sdp { +public: + DefaultSdp(int payload_type, const Track &track); + std::string getSdp() const override { return _printer; } + +private: + toolkit::_StrPrinter _printer; +}; + /** * sdp中除音视频外的其他描述部分 * Other description part in sdp except audio and video diff --git a/src/Rtsp/RtspMuxer.cpp b/src/Rtsp/RtspMuxer.cpp index 1e75a03f..684a16f8 100644 --- a/src/Rtsp/RtspMuxer.cpp +++ b/src/Rtsp/RtspMuxer.cpp @@ -65,14 +65,19 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) { WarnL << "Already add a track kind of: " << track->getTrackTypeStr() << ", ignore track: " << track->getCodecName(); return false; } + if (!track->ready()) { + WarnL << track->getCodecName() << " unready!"; + return false; + } auto &ref = _tracks[track->getIndex()]; auto &encoder = ref.encoder; CHECK(!encoder); + auto pt = RtpPayload::getPayloadType(*track); // payload type 96以后则为动态pt [AUTO-TRANSLATED:812ac0a2] // Payload type 96 and above is dynamic PT - Sdp::Ptr sdp = track->getSdp(96 + _index); + Sdp::Ptr sdp = track->getSdp(pt == -1 ? 96 + _index : pt); if (!sdp) { WarnL << "Unsupported codec: " << track->getCodecName(); return false;