修复单词拼错

This commit is contained in:
waken 2023-11-09 16:31:46 +08:00
commit a052e2c582
21 changed files with 111 additions and 59 deletions

@ -1 +1 @@
Subproject commit a4771b353d9ebe1bc162364237a31f4184a7c435 Subproject commit 12c2ec7b07dce1b6a0543d9979f5c5231f69e828

View File

@ -1758,10 +1758,16 @@
"value": "obs", "value": "obs",
"description": "流id例如 obs" "description": "流id例如 obs"
}, },
{
"key": "ssrc_multi_send",
"value": "0",
"description": "是否支持同ssrc推流到多个上级服务器,该参数非必选参数 默认false",
"disabled": true
},
{ {
"key": "ssrc", "key": "ssrc",
"value": "1", "value": "1",
"description": "rtp推流的ssrcssrc不同时可以推流到多个上级服务器" "description": "rtp推流的ssrc"
}, },
{ {
"key": "dst_url", "key": "dst_url",

View File

@ -1182,6 +1182,7 @@ void installWebApi() {
//回复json //回复json
val["port"] = port; val["port"] = port;
}); });
api_regist("/index/api/openRtpServerMultiplex", [](API_ARGS_MAP) { api_regist("/index/api/openRtpServerMultiplex", [](API_ARGS_MAP) {
CHECK_SECRET(); CHECK_SECRET();
CHECK_ARGS("port", "stream_id"); CHECK_ARGS("port", "stream_id");
@ -1263,6 +1264,7 @@ void installWebApi() {
args.passive = false; args.passive = false;
args.dst_url = allArgs["dst_url"]; args.dst_url = allArgs["dst_url"];
args.dst_port = allArgs["dst_port"]; args.dst_port = allArgs["dst_port"];
args.ssrc_multi_send = allArgs["ssrc_multi_send"].empty() ? false : allArgs["ssrc_multi_send"].as<bool>();
args.ssrc = allArgs["ssrc"]; args.ssrc = allArgs["ssrc"];
args.is_udp = allArgs["is_udp"]; args.is_udp = allArgs["is_udp"];
args.src_port = allArgs["src_port"]; args.src_port = allArgs["src_port"];

View File

@ -104,6 +104,8 @@ public:
bool passive = false; bool passive = false;
// rtp payload type // rtp payload type
uint8_t pt = 96; uint8_t pt = 96;
//是否支持同ssrc多服务器发送
bool ssrc_multi_send = false;
// 指定rtp ssrc // 指定rtp ssrc
std::string ssrc; std::string ssrc;
// 指定本地发送端口 // 指定本地发送端口

View File

@ -45,6 +45,7 @@ static string getTrackInfoStr(const TrackSource *track_src){
_StrPrinter codec_info; _StrPrinter codec_info;
auto tracks = track_src->getTracks(true); auto tracks = track_src->getTracks(true);
for (auto &track : tracks) { for (auto &track : tracks) {
track->update();
auto codec_type = track->getTrackType(); auto codec_type = track->getTrackType();
codec_info << track->getCodecName(); codec_info << track->getCodecName();
switch (codec_type) { switch (codec_type) {
@ -290,12 +291,14 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE
auto ring = _ring; auto ring = _ring;
auto ssrc = args.ssrc; auto ssrc = args.ssrc;
auto ssrc_multi_send = args.ssrc_multi_send;
auto tracks = getTracks(false); auto tracks = getTracks(false);
auto poller = getOwnerPoller(sender); auto poller = getOwnerPoller(sender);
auto rtp_sender = std::make_shared<RtpSender>(poller); auto rtp_sender = std::make_shared<RtpSender>(poller);
weak_ptr<MultiMediaSourceMuxer> weak_self = shared_from_this(); weak_ptr<MultiMediaSourceMuxer> weak_self = shared_from_this();
rtp_sender->startSend(args, [ssrc, weak_self, rtp_sender, cb, tracks, ring, poller](uint16_t local_port, const SockException &ex) mutable { rtp_sender->startSend(args, [ssrc,ssrc_multi_send, weak_self, rtp_sender, cb, tracks, ring, poller](uint16_t local_port, const SockException &ex) mutable {
cb(local_port, ex); cb(local_port, ex);
auto strong_self = weak_self.lock(); auto strong_self = weak_self.lock();
if (!strong_self || ex) { if (!strong_self || ex) {
@ -324,7 +327,10 @@ void MultiMediaSourceMuxer::startSendRtp(MediaSource &sender, const MediaSourceE
// 可能归属线程发生变更 // 可能归属线程发生变更
strong_self->getOwnerPoller(MediaSource::NullMediaSource())->async([=]() { strong_self->getOwnerPoller(MediaSource::NullMediaSource())->async([=]() {
strong_self->_rtp_sender[ssrc] = std::move(reader); if(!ssrc_multi_send) {
strong_self->_rtp_sender.erase(ssrc);
}
strong_self->_rtp_sender.emplace(ssrc,reader);
}); });
}); });
#else #else

View File

@ -168,7 +168,7 @@ private:
toolkit::Ticker _last_check; toolkit::Ticker _last_check;
Stamp _stamp[2]; Stamp _stamp[2];
std::weak_ptr<Listener> _track_listener; std::weak_ptr<Listener> _track_listener;
std::unordered_map<std::string, RingType::RingReader::Ptr> _rtp_sender; std::unordered_multimap<std::string, RingType::RingReader::Ptr> _rtp_sender;
FMP4MediaSourceMuxer::Ptr _fmp4; FMP4MediaSourceMuxer::Ptr _fmp4;
RtmpMediaSourceMuxer::Ptr _rtmp; RtmpMediaSourceMuxer::Ptr _rtmp;
RtspMediaSourceMuxer::Ptr _rtsp; RtspMediaSourceMuxer::Ptr _rtsp;

View File

@ -21,53 +21,56 @@ namespace mediakit{
#ifndef ENABLE_MP4 #ifndef ENABLE_MP4
unsigned const samplingFrequencyTable[16] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0 }; unsigned const samplingFrequencyTable[16] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0 };
class AdtsHeader{ class AdtsHeader {
public: public:
unsigned int syncword = 0; //12 bslbf 同步字The bit string 1111 1111 1111说明一个ADTS帧的开始 unsigned int syncword = 0; // 12 bslbf 同步字The bit string 1111 1111 1111说明一个ADTS帧的开始
unsigned int id; //1 bslbf MPEG 标示符, 设置为1 unsigned int id; // 1 bslbf MPEG 标示符, 设置为1
unsigned int layer; //2 uimsbf Indicates which layer is used. Set to 00 unsigned int layer; // 2 uimsbf Indicates which layer is used. Set to 00
unsigned int protection_absent; //1 bslbf 表示是否误码校验 unsigned int protection_absent; // 1 bslbf 表示是否误码校验
unsigned int profile; //2 uimsbf 表示使用哪个级别的AAC如01 Low Complexity(LC)--- AACLC unsigned int profile; // 2 uimsbf 表示使用哪个级别的AAC如01 Low Complexity(LC)--- AACLC
unsigned int sf_index; //4 uimsbf 表示使用的采样率下标 unsigned int sf_index; // 4 uimsbf 表示使用的采样率下标
unsigned int private_bit; //1 bslbf unsigned int private_bit; // 1 bslbf
unsigned int channel_configuration; //3 uimsbf 表示声道数 unsigned int channel_configuration; // 3 uimsbf 表示声道数
unsigned int original; //1 bslbf unsigned int original; // 1 bslbf
unsigned int home; //1 bslbf unsigned int home; // 1 bslbf
//下面的为改变的参数即每一帧都不同 // 下面的为改变的参数即每一帧都不同
unsigned int copyright_identification_bit; //1 bslbf unsigned int copyright_identification_bit; // 1 bslbf
unsigned int copyright_identification_start; //1 bslbf unsigned int copyright_identification_start; // 1 bslbf
unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 说明是码率可变的码流 unsigned int adts_buffer_fullness; // 11 bslbf 0x7FF 说明是码率可变的码流
//no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧. // no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
//所以说number_of_raw_data_blocks_in_frame == 0 // 所以说number_of_raw_data_blocks_in_frame == 0
//表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据) // 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
unsigned int no_raw_data_blocks_in_frame; //2 uimsfb unsigned int no_raw_data_blocks_in_frame; // 2 uimsfb
}; };
static void dumpAdtsHeader(const AdtsHeader &hed, uint8_t *out) { static void dumpAdtsHeader(const AdtsHeader &hed, uint8_t *out) {
out[0] = (hed.syncword >> 4 & 0xFF); //8bit out[0] = (hed.syncword >> 4 & 0xFF); // 8bit
out[1] = (hed.syncword << 4 & 0xF0); //4 bit out[1] = (hed.syncword << 4 & 0xF0); // 4 bit
out[1] |= (hed.id << 3 & 0x08); //1 bit out[1] |= (hed.id << 3 & 0x08); // 1 bit
out[1] |= (hed.layer << 1 & 0x06); //2bit out[1] |= (hed.layer << 1 & 0x06); // 2bit
out[1] |= (hed.protection_absent & 0x01); //1 bit out[1] |= (hed.protection_absent & 0x01); // 1 bit
out[2] = (hed.profile << 6 & 0xC0); // 2 bit out[2] = (hed.profile << 6 & 0xC0); // 2 bit
out[2] |= (hed.sf_index << 2 & 0x3C); //4bit out[2] |= (hed.sf_index << 2 & 0x3C); // 4bit
out[2] |= (hed.private_bit << 1 & 0x02); //1 bit out[2] |= (hed.private_bit << 1 & 0x02); // 1 bit
out[2] |= (hed.channel_configuration >> 2 & 0x03); //1 bit out[2] |= (hed.channel_configuration >> 2 & 0x03); // 1 bit
out[3] = (hed.channel_configuration << 6 & 0xC0); // 2 bit out[3] = (hed.channel_configuration << 6 & 0xC0); // 2 bit
out[3] |= (hed.original << 5 & 0x20); //1 bit out[3] |= (hed.original << 5 & 0x20); // 1 bit
out[3] |= (hed.home << 4 & 0x10); //1 bit out[3] |= (hed.home << 4 & 0x10); // 1 bit
out[3] |= (hed.copyright_identification_bit << 3 & 0x08); //1 bit out[3] |= (hed.copyright_identification_bit << 3 & 0x08); // 1 bit
out[3] |= (hed.copyright_identification_start << 2 & 0x04); //1 bit out[3] |= (hed.copyright_identification_start << 2 & 0x04); // 1 bit
out[3] |= (hed.aac_frame_length >> 11 & 0x03); //2 bit out[3] |= (hed.aac_frame_length >> 11 & 0x03); // 2 bit
out[4] = (hed.aac_frame_length >> 3 & 0xFF); //8 bit out[4] = (hed.aac_frame_length >> 3 & 0xFF); // 8 bit
out[5] = (hed.aac_frame_length << 5 & 0xE0); //3 bit out[5] = (hed.aac_frame_length << 5 & 0xE0); // 3 bit
out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F); //5 bit out[5] |= (hed.adts_buffer_fullness >> 6 & 0x1F); // 5 bit
out[6] = (hed.adts_buffer_fullness << 2 & 0xFC); //6 bit out[6] = (hed.adts_buffer_fullness << 2 & 0xFC); // 6 bit
out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03); //2 bit out[6] |= (hed.no_raw_data_blocks_in_frame & 0x03); // 2 bit
} }
static void parseAacConfig(const string &config, AdtsHeader &adts) { static bool parseAacConfig(const string &config, AdtsHeader &adts) {
if (config.size() < 2) {
return false;
}
uint8_t cfg1 = config[0]; uint8_t cfg1 = config[0];
uint8_t cfg2 = config[1]; uint8_t cfg2 = config[1];
@ -94,6 +97,7 @@ static void parseAacConfig(const string &config, AdtsHeader &adts) {
adts.aac_frame_length = 7; adts.aac_frame_length = 7;
adts.adts_buffer_fullness = 2047; adts.adts_buffer_fullness = 2047;
adts.no_raw_data_blocks_in_frame = 0; adts.no_raw_data_blocks_in_frame = 0;
return true;
} }
#endif// ENABLE_MP4 #endif// ENABLE_MP4
@ -168,10 +172,12 @@ int dumpAacConfig(const string &config, size_t length, uint8_t *out, size_t out_
#endif #endif
} }
bool parseAacConfig(const string &config, int &samplerate, int &channels){ bool parseAacConfig(const string &config, int &samplerate, int &channels) {
#ifndef ENABLE_MP4 #ifndef ENABLE_MP4
AdtsHeader header; AdtsHeader header;
parseAacConfig(config, header); if (!parseAacConfig(config, header)) {
return false;
}
samplerate = samplingFrequencyTable[header.sf_index]; samplerate = samplingFrequencyTable[header.sf_index];
channels = header.channel_configuration; channels = header.channel_configuration;
return true; return true;
@ -326,11 +332,14 @@ bool AACTrack::inputFrame_l(const Frame::Ptr &frame) {
return false; return false;
} }
bool AACTrack::update() {
return parseAacConfig(_cfg, _sampleRate, _channel);
}
void AACTrack::onReady() { void AACTrack::onReady() {
if (_cfg.size() < 2) { if (!parseAacConfig(_cfg, _sampleRate, _channel)) {
return; _cfg.clear();
} }
parseAacConfig(_cfg, _sampleRate, _channel);
} }
Track::Ptr AACTrack::clone() { Track::Ptr AACTrack::clone() {
@ -342,6 +351,7 @@ Sdp::Ptr AACTrack::getSdp() {
WarnL << getCodecName() << " Track未准备好"; WarnL << getCodecName() << " Track未准备好";
return nullptr; return nullptr;
} }
update();
return std::make_shared<AACSdp>(getConfig(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024); return std::make_shared<AACSdp>(getConfig(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
} }

View File

@ -52,6 +52,7 @@ public:
int getAudioSampleRate() const override; int getAudioSampleRate() const override;
int getAudioSampleBit() const override; int getAudioSampleBit() const override;
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
bool update() override;
private: private:
void onReady(); void onReady();

View File

@ -168,6 +168,10 @@ bool H264Track::inputFrame(const Frame::Ptr &frame) {
return ret; return ret;
} }
bool H264Track::update() {
return getAVCInfo(_sps, _width, _height, _fps);
}
void H264Track::onReady() { void H264Track::onReady() {
if (!getAVCInfo(_sps, _width, _height, _fps)) { if (!getAVCInfo(_sps, _width, _height, _fps)) {
_sps.clear(); _sps.clear();

View File

@ -128,6 +128,7 @@ public:
int getVideoWidth() const override; int getVideoWidth() const override;
float getVideoFps() const override; float getVideoFps() const override;
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
bool update() override;
private: private:
void onReady(); void onReady();

View File

@ -44,13 +44,15 @@ H264Frame::Ptr H264RtpDecoder::obtainFrame() {
bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) { bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
auto seq = rtp->getSeq(); auto seq = rtp->getSeq();
auto ret = decodeRtp(rtp); auto last_is_gop = _is_gop;
if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) { _is_gop = decodeRtp(rtp);
if (!_gop_dropped && seq != (uint16_t)(_last_seq + 1) && _last_seq) {
_gop_dropped = true; _gop_dropped = true;
WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString(); WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
} }
_last_seq = seq; _last_seq = seq;
return ret; // 确保有sps rtp的时候gop从sps开始否则从关键帧开始
return _is_gop && !last_is_gop;
} }
/* /*
@ -74,7 +76,7 @@ bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
_frame->_buffer.assign("\x00\x00\x00\x01", 4); _frame->_buffer.assign("\x00\x00\x00\x01", 4);
_frame->_buffer.append((char *) ptr, size); _frame->_buffer.append((char *) ptr, size);
_frame->_pts = stamp; _frame->_pts = stamp;
auto key = _frame->keyFrame(); auto key = _frame->keyFrame() || _frame->configFrame();
outputFrame(rtp, _frame); outputFrame(rtp, _frame);
return key; return key;
} }
@ -127,7 +129,7 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
if (!fu->end_bit) { if (!fu->end_bit) {
//非末尾包 //非末尾包
return fu->start_bit ? _frame->keyFrame() : false; return fu->start_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
} }
//确保下一次fu必须收到第一个包 //确保下一次fu必须收到第一个包

View File

@ -51,6 +51,7 @@ private:
void outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame); void outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame);
private: private:
bool _is_gop = false;
bool _gop_dropped = false; bool _gop_dropped = false;
bool _fu_dropped = true; bool _fu_dropped = true;
uint16_t _last_seq = 0; uint16_t _last_seq = 0;

View File

@ -144,6 +144,10 @@ bool H265Track::inputFrame_l(const Frame::Ptr &frame) {
return ret; return ret;
} }
bool H265Track::update() {
return getHEVCInfo(_vps, _sps, _width, _height, _fps);
}
void H265Track::onReady() { void H265Track::onReady() {
if (!getHEVCInfo(_vps, _sps, _width, _height, _fps)) { if (!getHEVCInfo(_vps, _sps, _width, _height, _fps)) {
_vps.clear(); _vps.clear();

View File

@ -150,6 +150,7 @@ public:
int getVideoHeight() const override; int getVideoHeight() const override;
float getVideoFps() const override; float getVideoFps() const override;
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
bool update() override;
private: private:
void onReady(); void onReady();

View File

@ -163,7 +163,7 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
if (!e_bit) { if (!e_bit) {
//非末尾包 //非末尾包
return s_bit ? _frame->keyFrame() : false; return s_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
} }
//确保下一次fu必须收到第一个包 //确保下一次fu必须收到第一个包
@ -175,13 +175,15 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) { bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
auto seq = rtp->getSeq(); auto seq = rtp->getSeq();
auto ret = decodeRtp(rtp); auto last_is_gop = _is_gop;
_is_gop = decodeRtp(rtp);
if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) { if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) {
_gop_dropped = true; _gop_dropped = true;
WarnL << "start drop h265 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString(); WarnL << "start drop h265 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
} }
_last_seq = seq; _last_seq = seq;
return ret; // 确保有sps rtp的时候gop从sps开始否则从关键帧开始
return _is_gop && !last_is_gop;
} }
bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) { bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
@ -220,7 +222,7 @@ bool H265RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
_frame->_buffer.assign("\x00\x00\x00\x01", 4); _frame->_buffer.assign("\x00\x00\x00\x01", 4);
_frame->_buffer.append((char *) ptr, size); _frame->_buffer.append((char *) ptr, size);
_frame->_pts = stamp; _frame->_pts = stamp;
auto key = _frame->keyFrame(); auto key = _frame->keyFrame() || _frame->configFrame();
outputFrame(rtp, _frame); outputFrame(rtp, _frame);
return key; return key;
} }

View File

@ -51,6 +51,7 @@ private:
void outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame); void outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame);
private: private:
bool _is_gop = false;
bool _using_donl_field = false; bool _using_donl_field = false;
bool _gop_dropped = false; bool _gop_dropped = false;
bool _fu_dropped = true; bool _fu_dropped = true;

View File

@ -39,6 +39,11 @@ public:
*/ */
virtual Track::Ptr clone() = 0; virtual Track::Ptr clone() = 0;
/**
* track信息sps/pps解析
*/
virtual bool update() { return false; }
/** /**
* sdp * sdp
* @return sdp对象 * @return sdp对象

View File

@ -80,7 +80,7 @@ void HttpClient::sendRequest(const string &url) {
} }
if (!alive() || host_changed) { if (!alive() || host_changed) {
startConnect(host, port, _wait_header_ms); startConnect(host, port, _wait_header_ms / 1000.0f);
} else { } else {
SockException ex; SockException ex;
onConnect_l(ex); onConnect_l(ex);

View File

@ -70,6 +70,7 @@ void PlayerProxy::setTranslationInfo()
_transtalion_info.stream_info.clear(); _transtalion_info.stream_info.clear();
auto tracks = _muxer->getTracks(); auto tracks = _muxer->getTracks();
for (auto &track : tracks) { for (auto &track : tracks) {
track->update();
_transtalion_info.stream_info.emplace_back(); _transtalion_info.stream_info.emplace_back();
auto &back = _transtalion_info.stream_info.back(); auto &back = _transtalion_info.stream_info.back();
back.bitrate = track->getBitRate(); back.bitrate = track->getBitRate();

View File

@ -198,6 +198,7 @@ bool MP4MuxerInterface::addTrack(const Track::Ptr &track) {
return false; return false;
} }
track->update();
switch (track->getCodecId()) { switch (track->getCodecId()) {
case CodecG711A: case CodecG711A:
case CodecG711U: case CodecG711U:

View File

@ -57,6 +57,7 @@ AudioMeta::AudioMeta(const AudioTrack::Ptr &audio) {
} }
uint8_t getAudioRtmpFlags(const Track::Ptr &track) { uint8_t getAudioRtmpFlags(const Track::Ptr &track) {
track->update();
switch (track->getTrackType()) { switch (track->getTrackType()) {
case TrackAudio: { case TrackAudio: {
auto audioTrack = std::dynamic_pointer_cast<AudioTrack>(track); auto audioTrack = std::dynamic_pointer_cast<AudioTrack>(track);
@ -115,6 +116,7 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track) {
void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) { void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) {
Metadata::Ptr new_metadata; Metadata::Ptr new_metadata;
track->update();
switch (track->getTrackType()) { switch (track->getTrackType()) {
case TrackVideo: { case TrackVideo: {
new_metadata = std::make_shared<VideoMeta>(std::dynamic_pointer_cast<VideoTrack>(track)); new_metadata = std::make_shared<VideoMeta>(std::dynamic_pointer_cast<VideoTrack>(track));