新增若干音视频编码类型的默认实现

部分支持VP8/VP9/AV1/JPEG/MP3/H266/ADPCM/SVAC/G722/G723/G729
This commit is contained in:
xia-chu 2024-11-29 23:38:27 +08:00
parent 87b42ab492
commit 892108d6ba
19 changed files with 202 additions and 266 deletions

View File

@ -37,6 +37,7 @@
- [谁在使用zlmediakit?](https://github.com/ZLMediaKit/ZLMediaKit/issues/511) - [谁在使用zlmediakit?](https://github.com/ZLMediaKit/ZLMediaKit/issues/511)
- 全面支持ipv6网络 - 全面支持ipv6网络
- 支持多轨道模式(一个流中多个视频/音频) - 支持多轨道模式(一个流中多个视频/音频)
- 全协议支持H264/H265/AAC/G711/OPUS部分支持VP8/VP9/AV1/JPEG/MP3/H266/ADPCM/SVAC/G722/G723/G729
## 项目定位 ## 项目定位

View File

@ -373,10 +373,6 @@ Track::Ptr AACTrack::clone() const {
} }
Sdp::Ptr AACTrack::getSdp(uint8_t payload_type) const { Sdp::Ptr AACTrack::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<AACSdp>(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10); return std::make_shared<AACSdp>(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10);
} }

View File

@ -19,70 +19,14 @@ using namespace toolkit;
namespace mediakit { 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 { Track::Ptr G711Track::clone() const {
return std::make_shared<G711Track>(*this); return std::make_shared<G711Track>(*this);
} }
Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const { Sdp::Ptr G711Track::getSdp(uint8_t payload_type) const {
if (!ready()) { return std::make_shared<DefaultSdp>(payload_type, *this);
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<G711Sdp>(codec, payload_type, sample_rate, audio_channel, bitrate);
}
namespace { namespace {
CodecId getCodecA() { CodecId getCodecA() {

View File

@ -357,10 +357,6 @@ private:
}; };
Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const { Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<H264Sdp>(_sps, _pps, payload_type, getBitRate() >> 10); return std::make_shared<H264Sdp>(_sps, _pps, payload_type, getBitRate() >> 10);
} }

View File

@ -263,10 +263,6 @@ private:
}; };
Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const { Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const {
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<H265Sdp>(_vps, _sps, _pps, payload_type, getBitRate() >> 10); return std::make_shared<H265Sdp>(_vps, _sps, _pps, payload_type, getBitRate() >> 10);
} }

View File

@ -31,25 +31,9 @@ void JPEGTrack::getVideoResolution(const uint8_t *buf, int len) {
} }
} }
class JPEGSdp : public Sdp { Sdp::Ptr JPEGTrack::getSdp(uint8_t pt) const {
public: return std::make_shared<DefaultSdp>(pt, *this);
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<JPEGSdp>(getBitRate() >> 10);
}
namespace { namespace {

View File

@ -18,50 +18,8 @@ using namespace toolkit;
namespace mediakit { 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 { Sdp::Ptr L16Track::getSdp(uint8_t payload_type) const {
WarnL << "Enter L16Track::getSdp function"; return std::make_shared<DefaultSdp>(payload_type, *this);
if (!ready()) {
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<L16Sdp>(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10);
} }
Track::Ptr L16Track::clone() const { Track::Ptr L16Track::clone() const {

View File

@ -18,51 +18,9 @@ using namespace toolkit;
namespace mediakit { 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 { Sdp::Ptr OpusTrack::getSdp(uint8_t payload_type) const {
if (!ready()) { return std::make_shared<DefaultSdp>(payload_type, *this);
WarnL << getCodecName() << " Track未准备好";
return nullptr;
}
return std::make_shared<OpusSdp>(payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10);
} }
namespace { namespace {

View File

@ -10,6 +10,8 @@
#include "Factory.h" #include "Factory.h"
#include "Rtmp/Rtmp.h" #include "Rtmp/Rtmp.h"
#include "CommonRtmp.h"
#include "CommonRtp.h"
#include "Common/config.h" #include "Common/config.h"
using namespace std; using namespace std;
@ -19,15 +21,6 @@ namespace mediakit {
static std::unordered_map<int, const CodecPlugin *> s_plugins; static std::unordered_map<int, const CodecPlugin *> 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(h264_plugin);
REGISTER_CODEC(h265_plugin); REGISTER_CODEC(h265_plugin);
REGISTER_CODEC(jpeg_plugin); REGISTER_CODEC(jpeg_plugin);
@ -51,8 +44,7 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
} }
auto it = s_plugins.find(codec); auto it = s_plugins.find(codec);
if (it == s_plugins.end()) { if (it == s_plugins.end()) {
WarnL << "Unsupported codec: " << track->getName(); return getTrackByCodecId(codec, track->_samplerate, track->_channel);
return nullptr;
} }
return it->second->getTrackBySdp(track); 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) { RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec, uint8_t pt) {
auto it = s_plugins.find(codec); auto it = s_plugins.find(codec);
if (it == s_plugins.end()) { if (it == s_plugins.end()) {
WarnL << "Unsupported codec: " << getCodecName(codec); WarnL << "Unsupported codec: " << getCodecName(codec) << ", use CommonRtpEncoder";
return nullptr; return std::make_shared<CommonRtpEncoder>();
} }
return it->second->getRtpEncoderByCodecId(pt); return it->second->getRtpEncoderByCodecId(pt);
} }
@ -78,8 +70,8 @@ RtpCodec::Ptr Factory::getRtpEncoderByCodecId(CodecId codec, uint8_t pt) {
RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) { RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) {
auto it = s_plugins.find(codec); auto it = s_plugins.find(codec);
if (it == s_plugins.end()) { if (it == s_plugins.end()) {
WarnL << "Unsupported codec: " << getCodecName(codec); WarnL << "Unsupported codec: " << getCodecName(codec) << ", use CommonRtpDecoder";
return nullptr; return std::make_shared<CommonRtpDecoder>(codec, 10 * 1024);
} }
return it->second->getRtpDecoderByCodecId(); return it->second->getRtpDecoderByCodecId();
} }
@ -117,8 +109,18 @@ static CodecId getVideoCodecIdByAmf(const AMFValue &val){
Track::Ptr Factory::getTrackByCodecId(CodecId codec, int sample_rate, int channels, int sample_bit) { Track::Ptr Factory::getTrackByCodecId(CodecId codec, int sample_rate, int channels, int sample_bit) {
auto it = s_plugins.find(codec); auto it = s_plugins.find(codec);
if (it == s_plugins.end()) { if (it == s_plugins.end()) {
WarnL << "Unsupported codec: " << getCodecName(codec); auto type = mediakit::getTrackType(codec);
return nullptr; switch (type) {
case TrackAudio: {
WarnL << "Unsupported codec: " << getCodecName(codec) << ", use default audio track";
return std::make_shared<AudioTrackImp>(codec, sample_rate, channels, sample_bit);
}
case TrackVideo: {
WarnL << "Unsupported codec: " << getCodecName(codec) << ", use default video track";
return std::make_shared<VideoTrackImp>(codec, 0, 0, 0);
}
default: WarnL << "Unsupported codec: " << getCodecName(codec); return nullptr;
}
} }
return it->second->getTrackByCodecId(sample_rate, channels, sample_bit); return it->second->getTrackByCodecId(sample_rate, channels, sample_bit);
} }
@ -145,13 +147,14 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) {
auto type_id = (RtmpAudioCodec)val.as_integer(); auto type_id = (RtmpAudioCodec)val.as_integer();
switch (type_id) { switch (type_id) {
case RtmpAudioCodec::aac: return CodecAAC; case RtmpAudioCodec::aac: return CodecAAC;
case RtmpAudioCodec::mp3: return CodecMP3;
case RtmpAudioCodec::adpcm: return CodecADPCM;
case RtmpAudioCodec::g711a: return CodecG711A; case RtmpAudioCodec::g711a: return CodecG711A;
case RtmpAudioCodec::g711u: return CodecG711U; case RtmpAudioCodec::g711u: return CodecG711U;
case RtmpAudioCodec::opus: return CodecOpus; case RtmpAudioCodec::opus: return CodecOpus;
default: WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid; default: WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid;
} }
} }
return CodecInvalid; return CodecInvalid;
} }
@ -166,8 +169,8 @@ Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int
RtmpCodec::Ptr Factory::getRtmpDecoderByTrack(const Track::Ptr &track) { RtmpCodec::Ptr Factory::getRtmpDecoderByTrack(const Track::Ptr &track) {
auto it = s_plugins.find(track->getCodecId()); auto it = s_plugins.find(track->getCodecId());
if (it == s_plugins.end()) { if (it == s_plugins.end()) {
WarnL << "Unsupported codec: " << track->getCodecName(); WarnL << "Unsupported codec: " << track->getCodecName() << ", use CommonRtmpDecoder";
return nullptr; return std::make_shared<CommonRtmpDecoder>(track);
} }
return it->second->getRtmpDecoderByTrack(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) { RtmpCodec::Ptr Factory::getRtmpEncoderByTrack(const Track::Ptr &track) {
auto it = s_plugins.find(track->getCodecId()); auto it = s_plugins.find(track->getCodecId());
if (it == s_plugins.end()) { if (it == s_plugins.end()) {
WarnL << "Unsupported codec: " << track->getCodecName(); WarnL << "Unsupported codec: " << track->getCodecName() << ", use CommonRtmpEncoder";
return nullptr; return std::make_shared<CommonRtmpEncoder>(track);
} }
return it->second->getRtmpEncoderByTrack(track); return it->second->getRtmpEncoderByTrack(track);
} }
@ -190,6 +193,8 @@ AMFValue Factory::getAmfByCodecId(CodecId codecId) {
case CodecG711A: return AMFValue((int)RtmpAudioCodec::g711a); case CodecG711A: return AMFValue((int)RtmpAudioCodec::g711a);
case CodecG711U: return AMFValue((int)RtmpAudioCodec::g711u); case CodecG711U: return AMFValue((int)RtmpAudioCodec::g711u);
case CodecOpus: return AMFValue((int)RtmpAudioCodec::opus); 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 CodecAV1: return AMFValue((int)RtmpVideoCodec::fourcc_av1);
case CodecVP9: return AMFValue((int)RtmpVideoCodec::fourcc_vp9); case CodecVP9: return AMFValue((int)RtmpVideoCodec::fourcc_vp9);
default: return AMFValue(AMF_NULL); default: return AMFValue(AMF_NULL);
@ -215,4 +220,3 @@ Frame::Ptr Factory::getFrameFromBuffer(CodecId codec, Buffer::Ptr data, uint64_t
} }
} // namespace mediakit } // namespace mediakit

View File

@ -23,6 +23,7 @@
#define REGISTER_STATIC_VAR(var_name, line) REGISTER_STATIC_VAR_INNER(var_name, line) #define REGISTER_STATIC_VAR(var_name, line) REGISTER_STATIC_VAR_INNER(var_name, line)
#define REGISTER_CODEC(plugin) \ #define REGISTER_CODEC(plugin) \
extern CodecPlugin plugin; \
static toolkit::onceToken REGISTER_STATIC_VAR(s_token, __LINE__) ([]() { \ static toolkit::onceToken REGISTER_STATIC_VAR(s_token, __LINE__) ([]() { \
Factory::registerPlugin(plugin); \ Factory::registerPlugin(plugin); \
}); });

View File

@ -43,7 +43,18 @@ typedef enum {
XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8, MOV_OBJECT_VP8) \ XX(CodecVP8, TrackVideo, 7, "VP8", PSI_STREAM_VP8, MOV_OBJECT_VP8) \
XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9, MOV_OBJECT_VP9) \ XX(CodecVP9, TrackVideo, 8, "VP9", PSI_STREAM_VP9, MOV_OBJECT_VP9) \
XX(CodecAV1, TrackVideo, 9, "AV1", PSI_STREAM_AV1, MOV_OBJECT_AV1) \ 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 { typedef enum {
CodecInvalid = -1, CodecInvalid = -1,

26
src/Extension/Track.cpp Normal file
View File

@ -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<DefaultSdp>(payload_type, *this);
}
Sdp::Ptr VideoTrackImp::getSdp(uint8_t payload_type) const {
return std::make_shared<DefaultSdp>(payload_type, *this);
}
} // namespace mediakit

View File

@ -201,7 +201,7 @@ public:
bool ready() const override { return true; } bool ready() const override { return true; }
Track::Ptr clone() const override { return std::make_shared<VideoTrackImp>(*this); } Track::Ptr clone() const override { return std::make_shared<VideoTrackImp>(*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; } CodecId getCodecId() const override { return _codec_id; }
private: private:
@ -298,7 +298,7 @@ public:
* [AUTO-TRANSLATED:9af5a0a4] * [AUTO-TRANSLATED:9af5a0a4]
*/ */
int getAudioSampleRate() const override{ int getAudioSampleRate() const override{
return _sample_rate; return _sample_rate ? _sample_rate : RtpPayload::getClockRateByCodec(_codecid);
} }
/** /**
@ -308,7 +308,7 @@ public:
* [AUTO-TRANSLATED:5fedc65d] * [AUTO-TRANSLATED:5fedc65d]
*/ */
int getAudioSampleBit() const override{ int getAudioSampleBit() const override{
return _sample_bit; return _sample_bit ? _sample_bit : 16;
} }
/** /**
@ -318,11 +318,11 @@ public:
* [AUTO-TRANSLATED:2613b317] * [AUTO-TRANSLATED:2613b317]
*/ */
int getAudioChannel() const override{ int getAudioChannel() const override{
return _channels; return _channels ? _channels : 1;
} }
Track::Ptr clone() const override { return std::make_shared<AudioTrackImp>(*this); } Track::Ptr clone() const override { return std::make_shared<AudioTrackImp>(*this); }
Sdp::Ptr getSdp(uint8_t payload_type) const override { return nullptr; } Sdp::Ptr getSdp(uint8_t payload_type) const override;
private: private:
CodecId _codecid; CodecId _codecid;

View File

@ -68,29 +68,23 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track) {
auto iChannel = audioTrack->getAudioChannel(); auto iChannel = audioTrack->getAudioChannel();
auto iSampleBit = audioTrack->getAudioSampleBit(); 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()) { switch (track->getCodecId()) {
case CodecG711A: flvAudioType = (uint8_t)RtmpAudioCodec::g711a; break; case CodecAAC:
case CodecG711U: flvAudioType = (uint8_t)RtmpAudioCodec::g711u; break;
case CodecOpus: { case CodecOpus: {
flvAudioType = (uint8_t)RtmpAudioCodec::opus; // opus/aac不通过flags获取音频相关信息 [AUTO-TRANSLATED:0ddf328b]
// opus不通过flags获取音频相关信息 [AUTO-TRANSLATED:0ddf328b] // opus/aac does not get audio information through flags
// opus does not get audio information through flags
iSampleRate = 44100; iSampleRate = 44100;
iSampleBit = 16; iSampleBit = 16;
iChannel = 2; iChannel = 2;
break; break;
} }
case CodecAAC: { default: break;
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;
} }
uint8_t flvSampleRate; uint8_t flvSampleRate;

View File

@ -371,6 +371,8 @@ enum class RtmpAudioCodec : uint8_t {
14 = MP3 8 kHz 14 = MP3 8 kHz
15 = Device-specific sound 15 = Device-specific sound
*/ */
adpcm = 1,
mp3 = 2,
g711a = 7, g711a = 7,
g711u = 8, g711u = 8,
aac = 10, aac = 10,

View File

@ -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传统只支持 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. // 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) { if (track) {
onTrack(stream, std::move(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]; auto &ref = _tracks[stream];
if (!ref.first) { if (!ref.first) {
onTrack(stream, Factory::getTrackByCodecId(codec, 8000, 1, 16)); onTrack(stream, Factory::getTrackByCodecId(codec));
} }
if (!ref.first) { if (!ref.first) {
WarnL << "Unsupported codec :" << getCodecName(codec); WarnL << "Unsupported codec :" << getCodecName(codec);

View File

@ -12,9 +12,10 @@
#include <cinttypes> #include <cinttypes>
#include <random> #include <random>
#include "Rtsp.h" #include "Rtsp.h"
#include "Network/Socket.h"
#include "Common/Parser.h" #include "Common/Parser.h"
#include "Common/config.h" #include "Common/config.h"
#include "Network/Socket.h" #include "Extension/Track.h"
#include "Extension/Factory.h" #include "Extension/Factory.h"
using namespace std; using namespace std;
@ -24,50 +25,84 @@ namespace mediakit {
int RtpPayload::getClockRate(int pt) { int RtpPayload::getClockRate(int pt) {
switch (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; case value: return clock_rate;
RTP_PT_MAP(SWITCH_CASE) RTP_PT_MAP(XX)
#undef SWITCH_CASE #undef XX
default: return 90000; default: return 90000;
} }
} }
int RtpPayload::getClockRateByCodec(CodecId codec) {
#define XX(name, type, value, clock_rate, channel, codec_id) { codec_id, clock_rate },
static map<CodecId, int> 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<CodecId, info> 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<const AudioTrack &>(track).getAudioSampleRate() != it->second.clock_rate
|| static_cast<const AudioTrack &>(track).getAudioChannel() != it->second.channels) {
return -1;
}
}
return it->second.pt;
}
TrackType RtpPayload::getTrackType(int pt) { TrackType RtpPayload::getTrackType(int pt) {
switch (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; case value: return type;
RTP_PT_MAP(SWITCH_CASE) RTP_PT_MAP(XX)
#undef SWITCH_CASE #undef XX
default: return TrackInvalid; default: return TrackInvalid;
} }
} }
int RtpPayload::getAudioChannel(int pt) { int RtpPayload::getAudioChannel(int pt) {
switch (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; case value: return channel;
RTP_PT_MAP(SWITCH_CASE) RTP_PT_MAP(XX)
#undef SWITCH_CASE #undef XX
default: return 1; default: return 1;
} }
} }
const char *RtpPayload::getName(int pt) { const char *RtpPayload::getName(int pt) {
switch (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; case value: return #name;
RTP_PT_MAP(SWITCH_CASE) RTP_PT_MAP(XX)
#undef SWITCH_CASE #undef XX
default: return "unknown payload type"; default: return "unknown payload type";
} }
} }
CodecId RtpPayload::getCodecId(int pt) { CodecId RtpPayload::getCodecId(int pt) {
switch (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; case value: return codec_id;
RTP_PT_MAP(SWITCH_CASE) RTP_PT_MAP(XX)
#undef SWITCH_CASE #undef XX
default: return CodecInvalid; default: return CodecInvalid;
} }
} }
@ -91,13 +126,7 @@ static void getAttrSdp(const multimap<string, string> &attr, _StrPrinter &printe
} }
string SdpTrack::getName() const { string SdpTrack::getName() const {
switch (_pt) { return RtpPayload::getName(_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;
}
} }
string SdpTrack::getControlUrl(const string &base_url) const { string SdpTrack::getControlUrl(const string &base_url) const {
@ -715,6 +744,23 @@ TitleSdp::TitleSdp(float dur_sec, const std::map<std::string, std::string> &head
_printer << "a=control:*\r\n"; _printer << "a=control:*\r\n";
} }
DefaultSdp::DefaultSdp(int payload_type, const Track &track)
: Sdp(track.getTrackType() == TrackVideo ? 9000 : static_cast<const AudioTrack &>(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<const AudioTrack &>(track).getAudioChannel();
}
_printer << "\r\n";
}
} // namespace mediakit } // namespace mediakit
namespace toolkit { namespace toolkit {

View File

@ -11,16 +11,18 @@
#ifndef RTSP_RTSP_H_ #ifndef RTSP_RTSP_H_
#define RTSP_RTSP_H_ #define RTSP_RTSP_H_
#include "Common/macros.h"
#include "Extension/Frame.h"
#include "Network/Socket.h"
#include <memory>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <memory>
#include <unordered_map> #include <unordered_map>
#include "Network/Socket.h"
#include "Common/macros.h"
#include "Extension/Frame.h"
namespace mediakit { namespace mediakit {
class Track;
namespace Rtsp { namespace Rtsp {
typedef enum { typedef enum {
RTP_Invalid = -1, RTP_Invalid = -1,
@ -32,27 +34,27 @@ typedef enum {
#define RTP_PT_MAP(XX) \ #define RTP_PT_MAP(XX) \
XX(PCMU, TrackAudio, 0, 8000, 1, CodecG711U) \ XX(PCMU, TrackAudio, 0, 8000, 1, CodecG711U) \
XX(GSM, TrackAudio, 3, 8000, 1, CodecInvalid) \ 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_8000, TrackAudio, 5, 8000, 1, CodecInvalid) \
XX(DVI4_16000, TrackAudio, 6, 16000, 1, CodecInvalid) \ XX(DVI4_16000, TrackAudio, 6, 16000, 1, CodecInvalid) \
XX(LPC, TrackAudio, 7, 8000, 1, CodecInvalid) \ XX(LPC, TrackAudio, 7, 8000, 1, CodecInvalid) \
XX(PCMA, TrackAudio, 8, 8000, 1, CodecG711A) \ 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_Stereo, TrackAudio, 10, 44100, 2, CodecInvalid) \
XX(L16_Mono, TrackAudio, 11, 44100, 1, CodecInvalid) \ XX(L16_Mono, TrackAudio, 11, 44100, 1, CodecInvalid) \
XX(QCELP, TrackAudio, 12, 8000, 1, CodecInvalid) \ XX(QCELP, TrackAudio, 12, 8000, 1, CodecInvalid) \
XX(CN, TrackAudio, 13, 8000, 1, CodecInvalid) \ XX(CN, TrackAudio, 13, 8000, 1, CodecInvalid) \
XX(MPA, TrackAudio, 14, 90000, 1, CodecInvalid) \ XX(MP3, TrackAudio, 14, 44100, 2, CodecMP3) \
XX(G728, TrackAudio, 15, 8000, 1, CodecInvalid) \ XX(G728, TrackAudio, 15, 8000, 1, CodecG728) \
XX(DVI4_11025, TrackAudio, 16, 11025, 1, CodecInvalid) \ XX(DVI4_11025, TrackAudio, 16, 11025, 1, CodecInvalid) \
XX(DVI4_22050, TrackAudio, 17, 22050, 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(CelB, TrackVideo, 25, 90000, 1, CodecInvalid) \
XX(JPEG, TrackVideo, 26, 90000, 1, CodecJPEG) \ XX(JPEG, TrackVideo, 26, 90000, 1, CodecJPEG) \
XX(nv, TrackVideo, 28, 90000, 1, CodecInvalid) \ XX(nv, TrackVideo, 28, 90000, 1, CodecInvalid) \
XX(H261, TrackVideo, 31, 90000, 1, CodecInvalid) \ XX(H261, TrackVideo, 31, 90000, 1, CodecInvalid) \
XX(MPV, TrackVideo, 32, 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) XX(H263, TrackVideo, 34, 90000, 1, CodecInvalid)
typedef enum { typedef enum {
@ -213,10 +215,12 @@ private:
class RtpPayload { class RtpPayload {
public: public:
static int getClockRate(int pt); static int getClockRate(int pt);
static int getClockRateByCodec(CodecId codec);
static TrackType getTrackType(int pt); static TrackType getTrackType(int pt);
static int getAudioChannel(int pt); static int getAudioChannel(int pt);
static const char *getName(int pt); static const char *getName(int pt);
static CodecId getCodecId(int pt); static CodecId getCodecId(int pt);
static int getPayloadType(const Track &track);
private: private:
RtpPayload() = delete; RtpPayload() = delete;
@ -243,8 +247,8 @@ public:
public: public:
int _pt = 0xff; int _pt = 0xff;
int _channel; int _channel = 0;
int _samplerate; int _samplerate = 0;
TrackType _type; TrackType _type;
std::string _codec; std::string _codec;
std::string _fmtp; std::string _fmtp;
@ -340,6 +344,15 @@ private:
uint32_t _sample_rate; 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中除音视频外的其他描述部分 * sdp中除音视频外的其他描述部分
* Other description part in sdp except audio and video * Other description part in sdp except audio and video

View File

@ -65,14 +65,19 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) {
WarnL << "Already add a track kind of: " << track->getTrackTypeStr() << ", ignore track: " << track->getCodecName(); WarnL << "Already add a track kind of: " << track->getTrackTypeStr() << ", ignore track: " << track->getCodecName();
return false; return false;
} }
if (!track->ready()) {
WarnL << track->getCodecName() << " unready!";
return false;
}
auto &ref = _tracks[track->getIndex()]; auto &ref = _tracks[track->getIndex()];
auto &encoder = ref.encoder; auto &encoder = ref.encoder;
CHECK(!encoder); CHECK(!encoder);
auto pt = RtpPayload::getPayloadType(*track);
// payload type 96以后则为动态pt [AUTO-TRANSLATED:812ac0a2] // payload type 96以后则为动态pt [AUTO-TRANSLATED:812ac0a2]
// Payload type 96 and above is dynamic PT // 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) { if (!sdp) {
WarnL << "Unsupported codec: " << track->getCodecName(); WarnL << "Unsupported codec: " << track->getCodecName();
return false; return false;