mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-23 03:10:04 +08:00
完善对无metadata的rtmp流的兼容性
This commit is contained in:
parent
e7f263b046
commit
41509800bc
@ -221,13 +221,27 @@ Track::Ptr Factory::getAudioTrackByAmf(const AMFValue& amf, int sample_rate, int
|
||||
return getTrackByCodecId(codecId, sample_rate, channels, sample_bit);
|
||||
}
|
||||
|
||||
RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track) {
|
||||
RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_encode) {
|
||||
switch (track->getCodecId()){
|
||||
case CodecH264 : return std::make_shared<H264RtmpEncoder>(track);
|
||||
case CodecAAC : return std::make_shared<AACRtmpEncoder>(track);
|
||||
case CodecH265 : return std::make_shared<H265RtmpEncoder>(track);
|
||||
case CodecG711A :
|
||||
case CodecG711U : return std::make_shared<G711RtmpEncoder>(track);
|
||||
case CodecG711U : {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
if (is_encode && (audio_track->getAudioSampleRate() != 8000 ||
|
||||
audio_track->getAudioChannel() != 1 ||
|
||||
audio_track->getAudioSampleBit() != 16)) {
|
||||
//rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711
|
||||
WarnL << "RTMP只支持8000/1/16规格的G711,目前规格是:"
|
||||
<< audio_track->getAudioSampleRate() << "/"
|
||||
<< audio_track->getAudioChannel() << "/"
|
||||
<< audio_track->getAudioSampleBit()
|
||||
<< ",该音频已被忽略";
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<G711RtmpEncoder>(track);
|
||||
}
|
||||
default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -59,8 +59,9 @@ public:
|
||||
/**
|
||||
* 根据Track获取Rtmp的编解码器
|
||||
* @param track 媒体描述对象
|
||||
* @param is_encode 是否为编码器还是解码器
|
||||
*/
|
||||
static RtmpCodec::Ptr getRtmpCodecByTrack(const Track::Ptr &track);
|
||||
static RtmpCodec::Ptr getRtmpCodecByTrack(const Track::Ptr &track, bool is_encode);
|
||||
|
||||
/**
|
||||
* 根据codecId获取rtmp的codec描述
|
||||
|
@ -100,4 +100,23 @@ uint8_t getAudioRtmpFlags(const Track::Ptr &track){
|
||||
}
|
||||
|
||||
|
||||
void Metadata::addTrack(AMFValue &metadata, const Track::Ptr &track) {
|
||||
Metadata::Ptr new_metadata;
|
||||
switch (track->getTrackType()) {
|
||||
case TrackVideo: {
|
||||
new_metadata = std::make_shared<VideoMeta>(dynamic_pointer_cast<VideoTrack>(track));
|
||||
}
|
||||
break;
|
||||
case TrackAudio: {
|
||||
new_metadata = std::make_shared<AudioMeta>(dynamic_pointer_cast<AudioTrack>(track));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
new_metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value) {
|
||||
metadata.set(key, value);
|
||||
});
|
||||
}
|
||||
}//namespace mediakit
|
@ -220,6 +220,8 @@ public:
|
||||
const AMFValue &getMetadata() const{
|
||||
return _metadata;
|
||||
}
|
||||
|
||||
static void addTrack(AMFValue &metadata, const Track::Ptr &track);
|
||||
protected:
|
||||
AMFValue _metadata;
|
||||
};
|
||||
@ -261,7 +263,6 @@ private:
|
||||
CodecId _codecId;
|
||||
};
|
||||
|
||||
|
||||
class AudioMeta : public Metadata{
|
||||
public:
|
||||
typedef std::shared_ptr<AudioMeta> Ptr;
|
||||
|
@ -13,60 +13,56 @@
|
||||
|
||||
namespace mediakit {
|
||||
|
||||
void RtmpDemuxer::loadMetaData(const AMFValue &val){
|
||||
bool RtmpDemuxer::loadMetaData(const AMFValue &val){
|
||||
bool ret = false;
|
||||
try {
|
||||
int audiosamplerate = 0;
|
||||
int audiochannels = 0;
|
||||
int audiosamplesize = 0;
|
||||
const AMFValue *audiocodecid = nullptr;
|
||||
const AMFValue *videocodecid = nullptr;
|
||||
|
||||
val.object_for_each([&](const string &key, const AMFValue &val) {
|
||||
if (key == "duration") {
|
||||
_fDuration = val.as_number();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == "audiosamplerate") {
|
||||
audiosamplerate = val.as_integer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == "audiosamplesize") {
|
||||
audiosamplesize = val.as_integer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == "stereo") {
|
||||
audiochannels = val.as_boolean() ? 2 : 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == "videocodecid") {
|
||||
//找到视频
|
||||
videocodecid = &val;
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == "audiocodecid") {
|
||||
//找到音频
|
||||
audiocodecid = &val;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (videocodecid) {
|
||||
//有视频
|
||||
ret = true;
|
||||
makeVideoTrack(*videocodecid);
|
||||
}
|
||||
|
||||
if (audiocodecid) {
|
||||
//有音频
|
||||
ret = true;
|
||||
makeAudioTrack(*audiocodecid, audiosamplerate, audiochannels, audiosamplesize);
|
||||
}
|
||||
} catch (std::exception &ex) {
|
||||
WarnL << ex.what();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
@ -105,7 +101,7 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
|
||||
_videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getVideoTrackByAmf(videoCodec));
|
||||
if (_videoTrack) {
|
||||
//生成rtmpCodec对象以便解码rtmp
|
||||
_videoRtmpDecoder = Factory::getRtmpCodecByTrack(_videoTrack);
|
||||
_videoRtmpDecoder = Factory::getRtmpCodecByTrack(_videoTrack, false);
|
||||
if (_videoRtmpDecoder) {
|
||||
//设置rtmp解码器代理,生成的frame写入该Track
|
||||
_videoRtmpDecoder->addDelegate(_videoTrack);
|
||||
@ -123,7 +119,7 @@ void RtmpDemuxer::makeAudioTrack(const AMFValue &audioCodec,int sample_rate, int
|
||||
_audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getAudioTrackByAmf(audioCodec, sample_rate, channels, sample_bit));
|
||||
if (_audioTrack) {
|
||||
//生成rtmpCodec对象以便解码rtmp
|
||||
_audioRtmpDecoder = Factory::getRtmpCodecByTrack(_audioTrack);
|
||||
_audioRtmpDecoder = Factory::getRtmpCodecByTrack(_audioTrack, false);
|
||||
if (_audioRtmpDecoder) {
|
||||
//设置rtmp解码器代理,生成的frame写入该Track
|
||||
_audioRtmpDecoder->addDelegate(_audioTrack);
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
RtmpDemuxer() = default;
|
||||
virtual ~RtmpDemuxer() = default;
|
||||
|
||||
void loadMetaData(const AMFValue &metadata);
|
||||
bool loadMetaData(const AMFValue &metadata);
|
||||
|
||||
/**
|
||||
* 开始解复用
|
||||
|
@ -49,9 +49,14 @@ public:
|
||||
* 设置metadata
|
||||
*/
|
||||
void setMetaData(const AMFValue &metadata) override{
|
||||
_demuxer->loadMetaData(metadata);
|
||||
if(!_demuxer->loadMetaData(metadata)){
|
||||
//该metadata无效,需要重新生成
|
||||
_metadata = metadata;
|
||||
_recreate_metadata = true;
|
||||
}else{
|
||||
RtmpMediaSource::setMetaData(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输入rtmp并解析
|
||||
@ -138,6 +143,11 @@ public:
|
||||
_muxer->addTrack(track);
|
||||
track->addDelegate(_muxer);
|
||||
}
|
||||
|
||||
if(_recreate_metadata){
|
||||
//需要重新生成metadata
|
||||
Metadata::addTrack(_metadata,track);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,11 +156,19 @@ public:
|
||||
void onAllTrackReady() override{
|
||||
setTrackSource(_muxer);
|
||||
_all_track_ready = true;
|
||||
|
||||
if(_recreate_metadata){
|
||||
//需要重新生成metadata
|
||||
RtmpMediaSource::setMetaData(_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RtmpDemuxer::Ptr _demuxer;
|
||||
MultiMediaSourceMuxer::Ptr _muxer;
|
||||
AMFValue _metadata;
|
||||
bool _all_track_ready = false;
|
||||
bool _recreate_metadata = false;
|
||||
};
|
||||
} /* namespace mediakit */
|
||||
|
||||
|
@ -23,47 +23,9 @@ RtmpMuxer::RtmpMuxer(const TitleMeta::Ptr &title) {
|
||||
}
|
||||
|
||||
void RtmpMuxer::addTrack(const Track::Ptr &track) {
|
||||
//根据track生产metadata
|
||||
Metadata::Ptr metadata;
|
||||
switch (track->getTrackType()){
|
||||
case TrackVideo:{
|
||||
metadata = std::make_shared<VideoMeta>(dynamic_pointer_cast<VideoTrack>(track));
|
||||
}
|
||||
break;
|
||||
case TrackAudio:{
|
||||
metadata = std::make_shared<AudioMeta>(dynamic_pointer_cast<AudioTrack>(track));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
switch (track->getCodecId()){
|
||||
case CodecG711A:
|
||||
case CodecG711U:{
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
if(!audio_track){
|
||||
return;
|
||||
}
|
||||
if (audio_track->getAudioSampleRate() != 8000 ||
|
||||
audio_track->getAudioChannel() != 1 ||
|
||||
audio_track->getAudioSampleBit() != 16) {
|
||||
WarnL << "RTMP只支持8000/1/16规格的G711,目前规格是:"
|
||||
<< audio_track->getAudioSampleRate() << "/"
|
||||
<< audio_track->getAudioChannel() << "/"
|
||||
<< audio_track->getAudioSampleBit()
|
||||
<< ",该音频已被忽略";
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default : break;
|
||||
}
|
||||
|
||||
auto &encoder = _encoder[track->getTrackType()];
|
||||
//生成rtmp编码器,克隆该Track,防止循环引用
|
||||
encoder = Factory::getRtmpCodecByTrack(track->clone());
|
||||
encoder = Factory::getRtmpCodecByTrack(track->clone(), true);
|
||||
if (!encoder) {
|
||||
return;
|
||||
}
|
||||
@ -71,10 +33,8 @@ void RtmpMuxer::addTrack(const Track::Ptr &track) {
|
||||
//设置rtmp输出环形缓存
|
||||
encoder->setRtmpRing(_rtmpRing);
|
||||
|
||||
//添加其metadata
|
||||
metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value){
|
||||
_metadata.set(key,value);
|
||||
});
|
||||
//添加metadata
|
||||
Metadata::addTrack(_metadata,track);
|
||||
}
|
||||
|
||||
void RtmpMuxer::inputFrame(const Frame::Ptr &frame) {
|
||||
|
@ -44,6 +44,7 @@ inline void AMFValue::destroy() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void AMFValue::init() {
|
||||
switch (_type) {
|
||||
case AMF_OBJECT:
|
||||
@ -60,14 +61,13 @@ inline void AMFValue::init() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(AMFType type) :
|
||||
_type(type) {
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
AMFValue::~AMFValue() {
|
||||
destroy();
|
||||
}
|
||||
@ -78,7 +78,6 @@ AMFValue::AMFValue(const char *s) :
|
||||
*_value.string = s;
|
||||
}
|
||||
|
||||
|
||||
AMFValue::AMFValue(const std::string &s) :
|
||||
_type(AMF_STRING) {
|
||||
init();
|
||||
@ -108,15 +107,7 @@ AMFValue::AMFValue(const AMFValue &from) :
|
||||
*this = from;
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(AMFValue &&from) {
|
||||
*this = std::forward<AMFValue>(from);
|
||||
}
|
||||
|
||||
AMFValue& AMFValue::operator = (const AMFValue &from) {
|
||||
return *this = const_cast<AMFValue &&>(from);
|
||||
|
||||
}
|
||||
AMFValue& AMFValue::operator =(AMFValue &&from) {
|
||||
destroy();
|
||||
_type = from._type;
|
||||
init();
|
||||
@ -144,7 +135,6 @@ AMFValue& AMFValue::operator =(AMFValue &&from) {
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
|
||||
}
|
||||
|
||||
void AMFValue::clear() {
|
||||
@ -236,7 +226,6 @@ string AMFValue::to_string() const{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const AMFValue& AMFValue::operator[](const char *str) const {
|
||||
if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
|
||||
throw std::runtime_error("AMF not a object");
|
||||
@ -338,6 +327,7 @@ AMFEncoder & AMFEncoder::operator <<(const char *s) {
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AMFEncoder & AMFEncoder::operator <<(const std::string &s) {
|
||||
if (!s.empty()) {
|
||||
buf += char(AMF0_STRING);
|
||||
@ -349,18 +339,22 @@ AMFEncoder & AMFEncoder::operator <<(const std::string &s) {
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AMFEncoder & AMFEncoder::operator <<(std::nullptr_t) {
|
||||
buf += char(AMF0_NULL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AMFEncoder & AMFEncoder::write_undefined() {
|
||||
buf += char(AMF0_UNDEFINED);
|
||||
return *this;
|
||||
|
||||
}
|
||||
|
||||
AMFEncoder & AMFEncoder::operator <<(const int n){
|
||||
return (*this) << (double)n;
|
||||
}
|
||||
|
||||
AMFEncoder & AMFEncoder::operator <<(const double n) {
|
||||
buf += char(AMF0_NUMBER);
|
||||
uint64_t encoded = 0;
|
||||
|
@ -40,6 +40,7 @@ public:
|
||||
typedef std::map<std::string, AMFValue> mapType;
|
||||
typedef std::vector<AMFValue> arrayType;
|
||||
|
||||
~AMFValue();
|
||||
AMFValue(AMFType type = AMF_NULL);
|
||||
AMFValue(const char *s);
|
||||
AMFValue(const std::string &s);
|
||||
@ -47,10 +48,7 @@ public:
|
||||
AMFValue(int i);
|
||||
AMFValue(bool b);
|
||||
AMFValue(const AMFValue &from);
|
||||
AMFValue(AMFValue &&from);
|
||||
AMFValue &operator = (const AMFValue &from);
|
||||
AMFValue &operator =(AMFValue &&from);
|
||||
~AMFValue();
|
||||
|
||||
void clear();
|
||||
AMFType type() const ;
|
||||
|
Loading…
Reference in New Issue
Block a user