mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-12-05 09:21:59 +08:00
Compare commits
12 Commits
2eaadd262f
...
47e13db0e3
Author | SHA1 | Date | |
---|---|---|---|
|
47e13db0e3 | ||
|
aa56576b0e | ||
|
d1f3961326 | ||
|
892108d6ba | ||
|
87b42ab492 | ||
|
67668c9f2c | ||
|
02a0b0402a | ||
|
64285b6b09 | ||
|
f5d5b71731 | ||
|
4f8127f6f1 | ||
|
78b00d9dc0 | ||
|
ea263b9205 |
@ -1 +1 @@
|
|||||||
Subproject commit cf83ebc62e65ae6f3b73bc5ebd06cb0b2da49fa5
|
Subproject commit 0658496d5fc7d238f41e10ea4d0a10113a8eed84
|
@ -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
|
||||||
|
|
||||||
## 项目定位
|
## 项目定位
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// /////////////////////////////////////////flv录制///////////////////////////////////////////// [AUTO-TRANSLATED:a084663f]
|
// /////////////////////////////////////////flv录制///////////////////////////////////////////// [AUTO-TRANSLATED:a084663f]
|
||||||
// /////////////////////////////////////////flv录制/////////////////////////////////////////////
|
// /////////////////////////////////////////flv录制///////////////////////////////////////////// [AUTO-TRANSLATED:dbe04ff9]
|
||||||
|
// /////////////////////////////////////////FLV recording/////////////////////////////////////////////
|
||||||
|
|
||||||
typedef struct mk_flv_recorder_t *mk_flv_recorder;
|
typedef struct mk_flv_recorder_t *mk_flv_recorder;
|
||||||
|
|
||||||
@ -64,7 +65,8 @@ API_EXPORT void API_CALL mk_flv_recorder_release(mk_flv_recorder ctx);
|
|||||||
API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *vhost, const char *app, const char *stream, const char *file_path);
|
API_EXPORT int API_CALL mk_flv_recorder_start(mk_flv_recorder ctx, const char *vhost, const char *app, const char *stream, const char *file_path);
|
||||||
|
|
||||||
// /////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// [AUTO-TRANSLATED:99c61c68]
|
// /////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// [AUTO-TRANSLATED:99c61c68]
|
||||||
// /////////////////////////////////////////hls/mp4录制/////////////////////////////////////////////
|
// /////////////////////////////////////////hls/mp4录制///////////////////////////////////////////// [AUTO-TRANSLATED:0f2773b8]
|
||||||
|
// /////////////////////////////////////////HLS/MP4 recording/////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取录制状态
|
* 获取录制状态
|
||||||
@ -133,6 +135,15 @@ API_EXPORT int API_CALL mk_recorder_stop(int type, const char *vhost, const char
|
|||||||
* @param file_path 文件路径
|
* @param file_path 文件路径
|
||||||
* @param file_repeat 循环解复用
|
* @param file_repeat 循环解复用
|
||||||
* @param ini 配置
|
* @param ini 配置
|
||||||
|
* Load MP4 list
|
||||||
|
* @param vhost Virtual host
|
||||||
|
* @param app App
|
||||||
|
* @param stream Stream ID
|
||||||
|
* @param file_path File path
|
||||||
|
* @param file_repeat Loop demux
|
||||||
|
* @param ini Configuration
|
||||||
|
|
||||||
|
* [AUTO-TRANSLATED:2fa2d09a]
|
||||||
*/
|
*/
|
||||||
API_EXPORT void API_CALL mk_load_mp4_file(const char *vhost, const char *app, const char *stream, const char *file_path, int file_repeat);
|
API_EXPORT void API_CALL mk_load_mp4_file(const char *vhost, const char *app, const char *stream, const char *file_path, int file_repeat);
|
||||||
API_EXPORT void API_CALL mk_load_mp4_file2(const char *vhost, const char *app, const char *stream, const char *file_path, int file_repeat, mk_ini ini);
|
API_EXPORT void API_CALL mk_load_mp4_file2(const char *vhost, const char *app, const char *stream, const char *file_path, int file_repeat, mk_ini ini);
|
||||||
|
@ -196,7 +196,7 @@ API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb func, void *use
|
|||||||
#ifdef ENABLE_MEM_DEBUG
|
#ifdef ENABLE_MEM_DEBUG
|
||||||
auto bytes = getTotalMemUsage();
|
auto bytes = getTotalMemUsage();
|
||||||
val["memory.memUsage"] = bytes;
|
val["memory.memUsage"] = bytes;
|
||||||
val["memory.memUsageMB"] = (int)(bytes / 1024 / 1024);
|
val["memory.memUsageMB"] = (int)(bytes >> 20);
|
||||||
val["memory.memBlock"] = getTotalMemBlock();
|
val["memory.memBlock"] = getTotalMemBlock();
|
||||||
static auto block_type_size = getBlockTypeSize();
|
static auto block_type_size = getBlockTypeSize();
|
||||||
{
|
{
|
||||||
@ -240,7 +240,7 @@ API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb func, void *use
|
|||||||
#ifdef ENABLE_MEM_DEBUG
|
#ifdef ENABLE_MEM_DEBUG
|
||||||
auto bytes = getThisThreadMemUsage();
|
auto bytes = getThisThreadMemUsage();
|
||||||
val["memUsage"] = bytes;
|
val["memUsage"] = bytes;
|
||||||
val["memUsageMB"] = bytes / 1024 / 1024;
|
val["memUsageMB"] = bytes >> 20;
|
||||||
val["memBlock"] = getThisThreadMemBlock();
|
val["memBlock"] = getThisThreadMemBlock();
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -373,11 +373,7 @@ 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()) {
|
return std::make_shared<AACSdp>(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() >> 10);
|
||||||
WarnL << getCodecName() << " Track未准备好";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return std::make_shared<AACSdp>(getExtraData()->toString(), payload_type, getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -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() {
|
||||||
@ -94,7 +38,7 @@ CodecId getCodecU() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Track::Ptr getTrackByCodecId_l(CodecId codec, int sample_rate, int channels, int sample_bit) {
|
Track::Ptr getTrackByCodecId_l(CodecId codec, int sample_rate, int channels, int sample_bit) {
|
||||||
return (sample_rate && channels && sample_bit) ? std::make_shared<G711Track>(codec, sample_rate, channels, sample_bit) : nullptr;
|
return std::make_shared<G711Track>(codec, sample_rate, 1, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::Ptr getTrackByCodecIdA(int sample_rate, int channels, int sample_bit) {
|
Track::Ptr getTrackByCodecIdA(int sample_rate, int channels, int sample_bit) {
|
||||||
@ -119,7 +63,7 @@ Track::Ptr getTrackBySdpU(const SdpTrack::Ptr &track) {
|
|||||||
|
|
||||||
RtpCodec::Ptr getRtpEncoderByCodecId_l(CodecId codec, uint8_t pt) {
|
RtpCodec::Ptr getRtpEncoderByCodecId_l(CodecId codec, uint8_t pt) {
|
||||||
if (pt == Rtsp::PT_PCMA || pt == Rtsp::PT_PCMU) {
|
if (pt == Rtsp::PT_PCMA || pt == Rtsp::PT_PCMU) {
|
||||||
return std::make_shared<G711RtpEncoder>(codec, 1);
|
return std::make_shared<G711RtpEncoder>(8000, 1);
|
||||||
}
|
}
|
||||||
return std::make_shared<CommonRtpEncoder>();
|
return std::make_shared<CommonRtpEncoder>();
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
G711RtpEncoder::G711RtpEncoder(CodecId codec, uint32_t channels){
|
G711RtpEncoder::G711RtpEncoder(int sample_rate, int channels, int sample_bit) {
|
||||||
_cache_frame = FrameImp::create();
|
_sample_rate = sample_rate;
|
||||||
_cache_frame->_codec_id = codec;
|
|
||||||
_channels = channels;
|
_channels = channels;
|
||||||
|
_sample_bit = sample_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void G711RtpEncoder::setOpt(int opt, const toolkit::Any ¶m) {
|
void G711RtpEncoder::setOpt(int opt, const toolkit::Any ¶m) {
|
||||||
@ -24,36 +24,24 @@ void G711RtpEncoder::setOpt(int opt, const toolkit::Any ¶m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
bool G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||||
auto dur = (_cache_frame->size() - _cache_frame->prefixSize()) / (8 * _channels);
|
auto ptr = frame->data() + frame->prefixSize();
|
||||||
auto next_pts = _cache_frame->pts() + dur;
|
auto size = frame->size() - frame->prefixSize();
|
||||||
if (next_pts == 0) {
|
_buffer.append(ptr, size);
|
||||||
_cache_frame->_pts = frame->pts();
|
_in_size += size;
|
||||||
} else {
|
_in_pts = frame->pts();
|
||||||
if ((next_pts + _pkt_dur_ms) < frame->pts()) { // 有丢包超过20ms
|
|
||||||
_cache_frame->_pts = frame->pts() - dur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_cache_frame->_buffer.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
|
|
||||||
|
|
||||||
auto stamp = _cache_frame->pts();
|
if (!_pkt_bytes) {
|
||||||
auto ptr = _cache_frame->data() + _cache_frame->prefixSize();
|
// G711压缩率固定是2倍
|
||||||
auto len = _cache_frame->size() - _cache_frame->prefixSize();
|
_pkt_bytes = _pkt_dur_ms * _channels * (_sample_bit / 8) * _sample_rate / 1000 / 2;
|
||||||
auto remain_size = len;
|
|
||||||
size_t max_size = 160 * _channels * _pkt_dur_ms / 20; // 20 ms per 160 byte
|
|
||||||
size_t n = 0;
|
|
||||||
bool mark = false;
|
|
||||||
while (remain_size >= max_size) {
|
|
||||||
assert(remain_size >= max_size);
|
|
||||||
const size_t rtp_size = max_size;
|
|
||||||
n++;
|
|
||||||
stamp += _pkt_dur_ms;
|
|
||||||
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackAudio, ptr, rtp_size, mark, stamp), false);
|
|
||||||
ptr += rtp_size;
|
|
||||||
remain_size -= rtp_size;
|
|
||||||
}
|
}
|
||||||
_cache_frame->_buffer.erase(0, n * max_size);
|
|
||||||
_cache_frame->_pts += (uint64_t)_pkt_dur_ms * n;
|
while (_buffer.size() >= _pkt_bytes) {
|
||||||
return len > 0;
|
_out_size += _pkt_bytes;
|
||||||
|
auto pts = _in_pts - (_in_size - _out_size) * (_pkt_dur_ms / (float)_pkt_bytes);
|
||||||
|
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackAudio, _buffer.data(), _pkt_bytes, false, pts), false);
|
||||||
|
_buffer.erase(0, _pkt_bytes);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mediakit
|
} // namespace mediakit
|
@ -29,15 +29,17 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
* @param codec 编码类型
|
* @param sample_rate 音频采样率
|
||||||
* @param channels 通道数
|
* @param channels 通道数
|
||||||
|
* @param sample_bit 音频采样位数
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param codec Encoding type
|
* @param sample_rate audio sample rate
|
||||||
* @param channels Number of channels
|
* @param channels Number of channels
|
||||||
|
* @param sample_bit audio sample bits
|
||||||
|
|
||||||
* [AUTO-TRANSLATED:dbbd593e]
|
* [AUTO-TRANSLATED:dbbd593e]
|
||||||
*/
|
*/
|
||||||
G711RtpEncoder(CodecId codec, uint32_t channels);
|
G711RtpEncoder(int sample_rate = 8000, int channels = 1, int sample_bit = 16);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入帧数据并编码成rtp
|
* 输入帧数据并编码成rtp
|
||||||
@ -51,9 +53,16 @@ public:
|
|||||||
void setOpt(int opt, const toolkit::Any ¶m) override;
|
void setOpt(int opt, const toolkit::Any ¶m) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t _channels = 1;
|
int _channels;
|
||||||
|
int _sample_rate;
|
||||||
|
int _sample_bit;
|
||||||
|
|
||||||
uint32_t _pkt_dur_ms = 20;
|
uint32_t _pkt_dur_ms = 20;
|
||||||
FrameImp::Ptr _cache_frame;
|
uint32_t _pkt_bytes = 0;
|
||||||
|
uint64_t _in_size = 0;
|
||||||
|
uint64_t _out_size = 0;
|
||||||
|
int64_t _in_pts = 0;
|
||||||
|
toolkit::BufferLikeString _buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -357,11 +357,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const {
|
Sdp::Ptr H264Track::getSdp(uint8_t payload_type) const {
|
||||||
if (!ready()) {
|
return std::make_shared<H264Sdp>(_sps, _pps, payload_type, getBitRate() >> 10);
|
||||||
WarnL << getCodecName() << " Track未准备好";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return std::make_shared<H264Sdp>(_sps, _pps, payload_type, getBitRate() / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -263,11 +263,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const {
|
Sdp::Ptr H265Track::getSdp(uint8_t payload_type) const {
|
||||||
if (!ready()) {
|
return std::make_shared<H265Sdp>(_vps, _sps, _pps, payload_type, getBitRate() >> 10);
|
||||||
WarnL << getCodecName() << " Track未准备好";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return std::make_shared<H265Sdp>(_vps, _sps, _pps, payload_type, getBitRate() / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -31,26 +31,10 @@ 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() / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
CodecId getCodec() {
|
CodecId getCodec() {
|
||||||
|
@ -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() / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::Ptr L16Track::clone() const {
|
Track::Ptr L16Track::clone() const {
|
||||||
|
@ -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() / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -570,7 +570,7 @@ void getStatisticJson(const function<void(Value &val)> &cb) {
|
|||||||
#ifdef ENABLE_MEM_DEBUG
|
#ifdef ENABLE_MEM_DEBUG
|
||||||
auto bytes = getTotalMemUsage();
|
auto bytes = getTotalMemUsage();
|
||||||
val["totalMemUsage"] = (Json::UInt64) bytes;
|
val["totalMemUsage"] = (Json::UInt64) bytes;
|
||||||
val["totalMemUsageMB"] = (int) (bytes / 1024 / 1024);
|
val["totalMemUsageMB"] = (int) (bytes >> 20);
|
||||||
val["totalMemBlock"] = (Json::UInt64) getTotalMemBlock();
|
val["totalMemBlock"] = (Json::UInt64) getTotalMemBlock();
|
||||||
static auto block_type_size = getBlockTypeSize();
|
static auto block_type_size = getBlockTypeSize();
|
||||||
{
|
{
|
||||||
@ -604,7 +604,7 @@ void getStatisticJson(const function<void(Value &val)> &cb) {
|
|||||||
auto bytes = getThisThreadMemUsage();
|
auto bytes = getThisThreadMemUsage();
|
||||||
val["threadName"] = getThreadName();
|
val["threadName"] = getThreadName();
|
||||||
val["threadMemUsage"] = (Json::UInt64) bytes;
|
val["threadMemUsage"] = (Json::UInt64) bytes;
|
||||||
val["threadMemUsageMB"] = (Json::UInt64) (bytes / 1024 / 1024);
|
val["threadMemUsageMB"] = (Json::UInt64) (bytes >> 20);
|
||||||
val["threadMemBlock"] = (Json::UInt64) getThisThreadMemBlock();
|
val["threadMemBlock"] = (Json::UInt64) getThisThreadMemBlock();
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
@ -87,7 +79,7 @@ RtpCodec::Ptr Factory::getRtpDecoderByCodecId(CodecId codec) {
|
|||||||
// ///////////////////////////rtmp相关/////////////////////////////////////////// [AUTO-TRANSLATED:da9645df]
|
// ///////////////////////////rtmp相关/////////////////////////////////////////// [AUTO-TRANSLATED:da9645df]
|
||||||
// ///////////////////////////rtmp related///////////////////////////////////////////
|
// ///////////////////////////rtmp related///////////////////////////////////////////
|
||||||
|
|
||||||
static CodecId getVideoCodecIdByAmf(const AMFValue &val){
|
static CodecId getVideoCodecIdByAmf(const AMFValue &val) {
|
||||||
if (val.type() == AMF_STRING) {
|
if (val.type() == AMF_STRING) {
|
||||||
auto str = val.as_string();
|
auto str = val.as_string();
|
||||||
if (str == "avc1") {
|
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) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::Ptr Factory::getVideoTrackByAmf(const AMFValue &amf) {
|
Track::Ptr Factory::getVideoTrackByAmf(const AMFValue &amf) {
|
||||||
CodecId codecId = getVideoCodecIdByAmf(amf);
|
CodecId codecId = getVideoCodecIdByAmf(amf);
|
||||||
if(codecId == CodecInvalid){
|
if (codecId == CodecInvalid) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return getTrackByCodecId(codecId);
|
return getTrackByCodecId(codecId);
|
||||||
@ -144,18 +146,19 @@ static CodecId getAudioCodecIdByAmf(const AMFValue &val) {
|
|||||||
if (val.type() != AMF_NULL) {
|
if (val.type() != AMF_NULL) {
|
||||||
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::g711a : return CodecG711A;
|
case RtmpAudioCodec::mp3: return CodecMP3;
|
||||||
case RtmpAudioCodec::g711u : return CodecG711U;
|
case RtmpAudioCodec::adpcm: return CodecADPCM;
|
||||||
case RtmpAudioCodec::opus : return CodecOpus;
|
case RtmpAudioCodec::g711a: return CodecG711A;
|
||||||
default : WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid;
|
case RtmpAudioCodec::g711u: return CodecG711U;
|
||||||
|
case RtmpAudioCodec::opus: return CodecOpus;
|
||||||
|
default: WarnL << "Unsupported codec: " << (int)type_id; return CodecInvalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
CodecId codecId = getAudioCodecIdByAmf(amf);
|
||||||
if (codecId == CodecInvalid) {
|
if (codecId == CodecInvalid) {
|
||||||
return nullptr;
|
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) {
|
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);
|
||||||
@ -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) {
|
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);
|
auto frame = Factory::getFrameFromPtr(codec, data->data(), data->size(), dts, pts);
|
||||||
if(!frame){
|
if (!frame) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_shared<FrameCacheAble>(frame, false, std::move(data));
|
return std::make_shared<FrameCacheAble>(frame, false, std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
} // namespace mediakit
|
||||||
|
|
||||||
|
@ -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); \
|
||||||
});
|
});
|
||||||
@ -64,7 +65,7 @@ public:
|
|||||||
|
|
||||||
* [AUTO-TRANSLATED:397b982e]
|
* [AUTO-TRANSLATED:397b982e]
|
||||||
*/
|
*/
|
||||||
static Track::Ptr getTrackByCodecId(CodecId codecId, int sample_rate = 0, int channels = 0, int sample_bit = 0);
|
static Track::Ptr getTrackByCodecId(CodecId codecId, int sample_rate = 0, int channels = 1, int sample_bit = 16);
|
||||||
|
|
||||||
// //////////////////////////////rtsp相关////////////////////////////////// [AUTO-TRANSLATED:884055ec]
|
// //////////////////////////////rtsp相关////////////////////////////////// [AUTO-TRANSLATED:884055ec]
|
||||||
// //////////////////////////////rtsp相关//////////////////////////////////
|
// //////////////////////////////rtsp相关//////////////////////////////////
|
||||||
|
@ -261,7 +261,7 @@ static bool isNeedMerge(CodecId codec){
|
|||||||
|
|
||||||
bool FrameMerger::inputFrame(const Frame::Ptr &frame, onOutput cb, BufferLikeString *buffer) {
|
bool FrameMerger::inputFrame(const Frame::Ptr &frame, onOutput cb, BufferLikeString *buffer) {
|
||||||
if (frame && !isNeedMerge(frame->getCodecId())) {
|
if (frame && !isNeedMerge(frame->getCodecId())) {
|
||||||
cb(frame->dts(), frame->pts(), frame, true);
|
cb(frame->dts(), frame->pts(), Frame::getCacheAbleFrame(frame), true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (willFlush(frame)) {
|
if (willFlush(frame)) {
|
||||||
|
@ -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
26
src/Extension/Track.cpp
Normal 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
|
@ -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;
|
||||||
|
@ -284,9 +284,9 @@ static bool makeFolderMenu(const string &httpPath, const string &strFullPath, st
|
|||||||
} else if (fileSize < 1024 * 1024) {
|
} else if (fileSize < 1024 * 1024) {
|
||||||
ss << fixed << setprecision(2) << " (" << fileSize / 1024.0 << "KB)";
|
ss << fixed << setprecision(2) << " (" << fileSize / 1024.0 << "KB)";
|
||||||
} else if (fileSize < 1024 * 1024 * 1024) {
|
} else if (fileSize < 1024 * 1024 * 1024) {
|
||||||
ss << fixed << setprecision(2) << " (" << fileSize / 1024 / 1024.0 << "MB)";
|
ss << fixed << setprecision(2) << " (" << (fileSize >> 10) / 1024.0 << "MB)";
|
||||||
} else {
|
} else {
|
||||||
ss << fixed << setprecision(2) << " (" << fileSize / 1024 / 1024 / 1024.0 << "GB)";
|
ss << fixed << setprecision(2) << " (" << (fileSize >> 20) / 1024.0 << "GB)";
|
||||||
}
|
}
|
||||||
ss << "</a></li>\r\n";
|
ss << "</a></li>\r\n";
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,14 @@ VideoMeta::VideoMeta(const VideoTrack::Ptr &video) {
|
|||||||
_metadata.set("framerate", video->getVideoFps());
|
_metadata.set("framerate", video->getVideoFps());
|
||||||
}
|
}
|
||||||
if (video->getBitRate()) {
|
if (video->getBitRate()) {
|
||||||
_metadata.set("videodatarate", video->getBitRate() / 1024);
|
_metadata.set("videodatarate", video->getBitRate() >> 10);
|
||||||
}
|
}
|
||||||
_metadata.set("videocodecid", Factory::getAmfByCodecId(video->getCodecId()));
|
_metadata.set("videocodecid", Factory::getAmfByCodecId(video->getCodecId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) {
|
AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) {
|
||||||
if (audio->getBitRate()) {
|
if (audio->getBitRate()) {
|
||||||
_metadata.set("audiodatarate", audio->getBitRate() / 1024);
|
_metadata.set("audiodatarate", audio->getBitRate() >> 10);
|
||||||
}
|
}
|
||||||
if (audio->getAudioSampleRate() > 0) {
|
if (audio->getAudioSampleRate() > 0) {
|
||||||
_metadata.set("audiosamplerate", audio->getAudioSampleRate());
|
_metadata.set("audiosamplerate", audio->getAudioSampleRate());
|
||||||
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -83,79 +83,76 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) {
|
|||||||
// Prevent too many pt types from causing memory overflow
|
// Prevent too many pt types from causing memory overflow
|
||||||
WarnL << "Rtp payload type more than 2 types: " << _rtp_receiver.size();
|
WarnL << "Rtp payload type more than 2 types: " << _rtp_receiver.size();
|
||||||
}
|
}
|
||||||
switch (pt) {
|
|
||||||
case Rtsp::PT_PCMA:
|
do {
|
||||||
case Rtsp::PT_PCMU: {
|
if (pt < 96) {
|
||||||
// CodecG711U or CodecG711A
|
auto codec = RtpPayload::getCodecId(pt);
|
||||||
ref = std::make_shared<RtpReceiverImp>(8000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
if (codec != CodecInvalid && codec != CodecTS) {
|
||||||
auto track = Factory::getTrackByCodecId(pt == Rtsp::PT_PCMU ? CodecG711U : CodecG711A, 8000, 1, 16);
|
auto sample_rate = RtpPayload::getClockRate(pt);
|
||||||
CHECK(track);
|
auto channels = RtpPayload::getAudioChannel(pt);
|
||||||
track->setIndex(pt);
|
ref = std::make_shared<RtpReceiverImp>(sample_rate, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
||||||
_interface->addTrack(track);
|
auto track = Factory::getTrackByCodecId(codec, sample_rate, channels);
|
||||||
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Rtsp::PT_JPEG: {
|
|
||||||
// mjpeg
|
|
||||||
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
|
||||||
auto track = Factory::getTrackByCodecId(CodecJPEG);
|
|
||||||
CHECK(track);
|
|
||||||
track->setIndex(pt);
|
|
||||||
_interface->addTrack(track);
|
|
||||||
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
if (pt == opus_pt) {
|
|
||||||
// opus负载 [AUTO-TRANSLATED:defa6a8d]
|
|
||||||
// opus payload
|
|
||||||
ref = std::make_shared<RtpReceiverImp>(48000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
|
||||||
auto track = Factory::getTrackByCodecId(CodecOpus);
|
|
||||||
CHECK(track);
|
CHECK(track);
|
||||||
track->setIndex(pt);
|
track->setIndex(pt);
|
||||||
_interface->addTrack(track);
|
_interface->addTrack(track);
|
||||||
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
||||||
} else if (pt == h265_pt) {
|
break;
|
||||||
// H265负载 [AUTO-TRANSLATED:61fbcf7f]
|
|
||||||
// H265 payload
|
|
||||||
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
|
||||||
auto track = Factory::getTrackByCodecId(CodecH265);
|
|
||||||
CHECK(track);
|
|
||||||
track->setIndex(pt);
|
|
||||||
_interface->addTrack(track);
|
|
||||||
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
|
||||||
} else if (pt == h264_pt) {
|
|
||||||
// H264负载 [AUTO-TRANSLATED:6f3fbb0d]
|
|
||||||
// H264 payload
|
|
||||||
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
|
||||||
auto track = Factory::getTrackByCodecId(CodecH264);
|
|
||||||
CHECK(track);
|
|
||||||
track->setIndex(pt);
|
|
||||||
_interface->addTrack(track);
|
|
||||||
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
|
||||||
} else {
|
|
||||||
if (pt != Rtsp::PT_MP2T && pt != ps_pt) {
|
|
||||||
WarnL << "Unknown rtp payload type(" << (int)pt << "), decode it as mpeg-ps or mpeg-ts";
|
|
||||||
}
|
|
||||||
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
|
||||||
// ts或ps负载 [AUTO-TRANSLATED:3ca31480]
|
|
||||||
// ts or ps payload
|
|
||||||
_rtp_decoder[pt] = std::make_shared<CommonRtpDecoder>(CodecInvalid, 32 * 1024);
|
|
||||||
// 设置dump目录 [AUTO-TRANSLATED:23c88ace]
|
|
||||||
// Set dump directory
|
|
||||||
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
|
|
||||||
if (!dump_dir.empty()) {
|
|
||||||
auto save_path = File::absolutePath(_media_info.stream + ".mpeg", dump_dir);
|
|
||||||
_save_file_ps.reset(File::create_file(save_path.data(), "wb"), [](FILE *fp) {
|
|
||||||
if (fp) {
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (pt == opus_pt) {
|
||||||
|
// opus负载 [AUTO-TRANSLATED:defa6a8d]
|
||||||
|
// opus payload
|
||||||
|
ref = std::make_shared<RtpReceiverImp>(48000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
||||||
|
auto track = Factory::getTrackByCodecId(CodecOpus);
|
||||||
|
CHECK(track);
|
||||||
|
track->setIndex(pt);
|
||||||
|
_interface->addTrack(track);
|
||||||
|
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
if (pt == h265_pt) {
|
||||||
|
// H265负载 [AUTO-TRANSLATED:61fbcf7f]
|
||||||
|
// H265 payload
|
||||||
|
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
||||||
|
auto track = Factory::getTrackByCodecId(CodecH265);
|
||||||
|
CHECK(track);
|
||||||
|
track->setIndex(pt);
|
||||||
|
_interface->addTrack(track);
|
||||||
|
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pt == h264_pt) {
|
||||||
|
// H264负载 [AUTO-TRANSLATED:6f3fbb0d]
|
||||||
|
// H264 payload
|
||||||
|
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
||||||
|
auto track = Factory::getTrackByCodecId(CodecH264);
|
||||||
|
CHECK(track);
|
||||||
|
track->setIndex(pt);
|
||||||
|
_interface->addTrack(track);
|
||||||
|
_rtp_decoder[pt] = Factory::getRtpDecoderByCodecId(track->getCodecId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pt != Rtsp::PT_MP2T && pt != ps_pt) {
|
||||||
|
WarnL << "Unknown rtp payload type(" << (int)pt << "), decode it as mpeg-ps or mpeg-ts";
|
||||||
|
}
|
||||||
|
ref = std::make_shared<RtpReceiverImp>(90000, [this](RtpPacket::Ptr rtp) { onRtpSorted(std::move(rtp)); });
|
||||||
|
// ts或ps负载 [AUTO-TRANSLATED:3ca31480]
|
||||||
|
// ts or ps payload
|
||||||
|
_rtp_decoder[pt] = std::make_shared<CommonRtpDecoder>(CodecInvalid, 32 * 1024);
|
||||||
|
// 设置dump目录 [AUTO-TRANSLATED:23c88ace]
|
||||||
|
// Set dump directory
|
||||||
|
GET_CONFIG(string, dump_dir, RtpProxy::kDumpDir);
|
||||||
|
if (!dump_dir.empty()) {
|
||||||
|
auto save_path = File::absolutePath(_media_info.stream + ".mpeg", dump_dir);
|
||||||
|
_save_file_ps.reset(File::create_file(save_path.data(), "wb"), [](FILE *fp) {
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
// 设置frame回调 [AUTO-TRANSLATED:dec7590f]
|
// 设置frame回调 [AUTO-TRANSLATED:dec7590f]
|
||||||
// Set frame callback
|
// Set frame callback
|
||||||
_rtp_decoder[pt]->addDelegate([this, pt](const Frame::Ptr &frame) {
|
_rtp_decoder[pt]->addDelegate([this, pt](const Frame::Ptr &frame) {
|
||||||
@ -169,11 +166,16 @@ bool GB28181Process::inputRtp(bool, const char *data, size_t data_len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GB28181Process::onRtpDecode(const Frame::Ptr &frame) {
|
void GB28181Process::onRtpDecode(const Frame::Ptr &frame) {
|
||||||
if (frame->getCodecId() != CodecInvalid) {
|
switch (frame->getCodecId()) {
|
||||||
// 这里不是ps或ts [AUTO-TRANSLATED:6f79ac69]
|
case CodecInvalid:
|
||||||
// This is not ps or ts
|
case CodecTS:
|
||||||
_interface->inputFrame(frame);
|
case CodecPS: break;
|
||||||
return;
|
|
||||||
|
default:
|
||||||
|
// 这里不是ps或ts [AUTO-TRANSLATED:6f79ac69]
|
||||||
|
// This is not ps or ts
|
||||||
|
_interface->inputFrame(frame);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这是TS或PS [AUTO-TRANSLATED:55782860]
|
// 这是TS或PS [AUTO-TRANSLATED:55782860]
|
||||||
|
@ -127,8 +127,7 @@ void RtpSession::onRtpPacket(const char *data, size_t len) {
|
|||||||
weak_ptr<RtpSession> weak_self = static_pointer_cast<RtpSession>(shared_from_this());
|
weak_ptr<RtpSession> weak_self = static_pointer_cast<RtpSession>(shared_from_this());
|
||||||
_process->setOnDetach([weak_self](const SockException &ex) {
|
_process->setOnDetach([weak_self](const SockException &ex) {
|
||||||
if (auto strong_self = weak_self.lock()) {
|
if (auto strong_self = weak_self.lock()) {
|
||||||
strong_self->_process = nullptr;
|
strong_self->safeShutdown(ex);
|
||||||
strong_self->shutdown(ex);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -29,7 +29,7 @@ foreach(TEST_SRC ${TEST_SRC_LIST})
|
|||||||
get_filename_component(TEST_EXE_NAME ${TEST_SRC} NAME_WE)
|
get_filename_component(TEST_EXE_NAME ${TEST_SRC} NAME_WE)
|
||||||
|
|
||||||
if(NOT PCAP_FOUND)
|
if(NOT PCAP_FOUND)
|
||||||
message(WARNING "PCAP 未找到")
|
# message(WARNING "PCAP 未找到")
|
||||||
if("${TEST_EXE_NAME}" MATCHES "test_rtp_pcap")
|
if("${TEST_EXE_NAME}" MATCHES "test_rtp_pcap")
|
||||||
continue()
|
continue()
|
||||||
endif()
|
endif()
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* LICENSE file in the root of the source tree. All contributing project authors
|
* 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.
|
* may be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
#ifdef ENABLE_MP4
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -261,3 +261,4 @@ int main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -84,7 +84,7 @@ static bool loadFile(const char *path){
|
|||||||
}
|
}
|
||||||
timeStamp_last = timeStamp;
|
timeStamp_last = timeStamp;
|
||||||
}
|
}
|
||||||
WarnL << total_size / 1024 << "KB";
|
WarnL << (total_size >> 10) << "KB";
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ static bool loadFile(const char *path, const EventPoller::Ptr &poller) {
|
|||||||
if (ps_decoder) {
|
if (ps_decoder) {
|
||||||
ps_decoder->input(text, lSize);
|
ps_decoder->input(text, lSize);
|
||||||
}
|
}
|
||||||
WarnL << lSize / 1024 << "KB";
|
WarnL << (lSize >> 10) << "KB";
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* LICENSE file in the root of the source tree. All contributing project authors
|
* 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.
|
* may be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
#ifdef ENABLE_MP4
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Util/logger.h"
|
#include "Util/logger.h"
|
||||||
@ -141,3 +141,4 @@ int main(int argc, char *argv[]) {
|
|||||||
// return domain("/Users/xiongziliang/Downloads/mp4/Quantum.mp4", "rtsp://127.0.0.1/live/rtsp_push");
|
// return domain("/Users/xiongziliang/Downloads/mp4/Quantum.mp4", "rtsp://127.0.0.1/live/rtsp_push");
|
||||||
return domain(argv[1], argv[2]);
|
return domain(argv[1], argv[2]);
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -89,7 +89,7 @@ static bool loadFile(const char *path, const EventPoller::Ptr &poller) {
|
|||||||
poller->doDelayTask(1, [do_read, total_size, process]() mutable {
|
poller->doDelayTask(1, [do_read, total_size, process]() mutable {
|
||||||
auto ret = do_read();
|
auto ret = do_read();
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
WarnL << *total_size / 1024 << "KB";
|
WarnL << (*total_size >> 10) << "KB";
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 353af1f60115767e57662107e30935ac6ef178a2
|
Subproject commit 6689195ac89462d40accd88f13dfde58902da57b
|
Loading…
Reference in New Issue
Block a user