mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 20:47:08 +08:00
修正metadata拼写错误,优化RtmpMediaSource注册机制,修复及时拉流不出画面的bug
This commit is contained in:
parent
8ae9f56110
commit
cb7c72d9d9
@ -45,7 +45,7 @@ public:
|
|||||||
bool bEnableMp4 = false
|
bool bEnableMp4 = false
|
||||||
){
|
){
|
||||||
if (bEanbleRtmp) {
|
if (bEanbleRtmp) {
|
||||||
_rtmp = std::make_shared<RtmpMediaSourceMuxer>(vhost, strApp, strId, std::make_shared<TitleMete>(dur_sec));
|
_rtmp = std::make_shared<RtmpMediaSourceMuxer>(vhost, strApp, strId, std::make_shared<TitleMeta>(dur_sec));
|
||||||
}
|
}
|
||||||
if (bEanbleRtsp) {
|
if (bEanbleRtsp) {
|
||||||
_rtsp = std::make_shared<RtspMediaSourceMuxer>(vhost, strApp, strId, std::make_shared<TitleSdp>(dur_sec));
|
_rtsp = std::make_shared<RtspMediaSourceMuxer>(vhost, strApp, strId, std::make_shared<TitleSdp>(dur_sec));
|
||||||
|
@ -197,7 +197,7 @@ CodecId Factory::getCodecIdByAmf(const AMFValue &val){
|
|||||||
return CodecInvalid;
|
return CodecInvalid;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
WarnL << "Metedata不存在相应的Track";
|
WarnL << "Metadata不存在相应的Track";
|
||||||
}
|
}
|
||||||
|
|
||||||
return CodecInvalid;
|
return CodecInvalid;
|
||||||
|
@ -73,14 +73,14 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据amf对象获取响应的Track
|
* 根据amf对象获取响应的Track
|
||||||
* @param amf rtmp metedata中的videocodecid或audiocodecid的值
|
* @param amf rtmp metadata中的videocodecid或audiocodecid的值
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static Track::Ptr getTrackByAmf(const AMFValue &amf);
|
static Track::Ptr getTrackByAmf(const AMFValue &amf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据amf对象获取相应的CodecId
|
* 根据amf对象获取相应的CodecId
|
||||||
* @param val rtmp metedata中的videocodecid或audiocodecid的值
|
* @param val rtmp metadata中的videocodecid或audiocodecid的值
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static CodecId getCodecIdByAmf(const AMFValue &val);
|
static CodecId getCodecIdByAmf(const AMFValue &val);
|
||||||
|
@ -27,35 +27,35 @@
|
|||||||
#include "Extension/Factory.h"
|
#include "Extension/Factory.h"
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
VideoMete::VideoMete(const VideoTrack::Ptr &video,int datarate ){
|
VideoMeta::VideoMeta(const VideoTrack::Ptr &video,int datarate ){
|
||||||
if(video->getVideoWidth() > 0 ){
|
if(video->getVideoWidth() > 0 ){
|
||||||
_metedata.set("width", video->getVideoWidth());
|
_metadata.set("width", video->getVideoWidth());
|
||||||
}
|
}
|
||||||
if(video->getVideoHeight() > 0 ){
|
if(video->getVideoHeight() > 0 ){
|
||||||
_metedata.set("height", video->getVideoHeight());
|
_metadata.set("height", video->getVideoHeight());
|
||||||
}
|
}
|
||||||
if(video->getVideoFps() > 0 ){
|
if(video->getVideoFps() > 0 ){
|
||||||
_metedata.set("framerate", video->getVideoFps());
|
_metadata.set("framerate", video->getVideoFps());
|
||||||
}
|
}
|
||||||
_metedata.set("videodatarate", datarate);
|
_metadata.set("videodatarate", datarate);
|
||||||
_codecId = video->getCodecId();
|
_codecId = video->getCodecId();
|
||||||
_metedata.set("videocodecid", Factory::getAmfByCodecId(_codecId));
|
_metadata.set("videocodecid", Factory::getAmfByCodecId(_codecId));
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioMete::AudioMete(const AudioTrack::Ptr &audio,int datarate){
|
AudioMeta::AudioMeta(const AudioTrack::Ptr &audio,int datarate){
|
||||||
_metedata.set("audiodatarate", datarate);
|
_metadata.set("audiodatarate", datarate);
|
||||||
if(audio->getAudioSampleRate() > 0){
|
if(audio->getAudioSampleRate() > 0){
|
||||||
_metedata.set("audiosamplerate", audio->getAudioSampleRate());
|
_metadata.set("audiosamplerate", audio->getAudioSampleRate());
|
||||||
}
|
}
|
||||||
if(audio->getAudioSampleBit() > 0){
|
if(audio->getAudioSampleBit() > 0){
|
||||||
_metedata.set("audiosamplesize", audio->getAudioSampleBit());
|
_metadata.set("audiosamplesize", audio->getAudioSampleBit());
|
||||||
}
|
}
|
||||||
if(audio->getAudioChannel() > 0){
|
if(audio->getAudioChannel() > 0){
|
||||||
_metedata.set("audiochannels", audio->getAudioChannel());
|
_metadata.set("audiochannels", audio->getAudioChannel());
|
||||||
_metedata.set("stereo", audio->getAudioChannel() > 1);
|
_metadata.set("stereo", audio->getAudioChannel() > 1);
|
||||||
}
|
}
|
||||||
_codecId = audio->getCodecId();
|
_codecId = audio->getCodecId();
|
||||||
_metedata.set("audiocodecid", Factory::getAmfByCodecId(_codecId));
|
_metadata.set("audiocodecid", Factory::getAmfByCodecId(_codecId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
@ -298,36 +298,36 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rtmp metedata基类,用于描述rtmp格式信息
|
* rtmp metadata基类,用于描述rtmp格式信息
|
||||||
*/
|
*/
|
||||||
class Metedata : public CodecInfo{
|
class Metadata : public CodecInfo{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<Metedata> Ptr;
|
typedef std::shared_ptr<Metadata> Ptr;
|
||||||
|
|
||||||
Metedata():_metedata(AMF_OBJECT){}
|
Metadata():_metadata(AMF_OBJECT){}
|
||||||
virtual ~Metedata(){}
|
virtual ~Metadata(){}
|
||||||
const AMFValue &getMetedata() const{
|
const AMFValue &getMetadata() const{
|
||||||
return _metedata;
|
return _metadata;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
AMFValue _metedata;
|
AMFValue _metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* metedata中除音视频外的其他描述部分
|
* metadata中除音视频外的其他描述部分
|
||||||
*/
|
*/
|
||||||
class TitleMete : public Metedata{
|
class TitleMeta : public Metadata{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<TitleMete> Ptr;
|
typedef std::shared_ptr<TitleMeta> Ptr;
|
||||||
|
|
||||||
TitleMete(float dur_sec = 0,
|
TitleMeta(float dur_sec = 0,
|
||||||
uint64_t fileSize = 0,
|
uint64_t fileSize = 0,
|
||||||
const map<string,string> &header = map<string,string>()){
|
const map<string,string> &header = map<string,string>()){
|
||||||
_metedata.set("duration", dur_sec);
|
_metadata.set("duration", dur_sec);
|
||||||
_metedata.set("fileSize", 0);
|
_metadata.set("fileSize", 0);
|
||||||
_metedata.set("server","ZLMediaKit");
|
_metadata.set("server","ZLMediaKit");
|
||||||
for (auto &pr : header){
|
for (auto &pr : header){
|
||||||
_metedata.set(pr.first, pr.second);
|
_metadata.set(pr.first, pr.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,12 +348,12 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class VideoMete : public Metedata{
|
class VideoMeta : public Metadata{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<VideoMete> Ptr;
|
typedef std::shared_ptr<VideoMeta> Ptr;
|
||||||
|
|
||||||
VideoMete(const VideoTrack::Ptr &video,int datarate = 5000);
|
VideoMeta(const VideoTrack::Ptr &video,int datarate = 5000);
|
||||||
virtual ~VideoMete(){}
|
virtual ~VideoMeta(){}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回音频或视频类型
|
* 返回音频或视频类型
|
||||||
@ -375,13 +375,13 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AudioMete : public Metedata{
|
class AudioMeta : public Metadata{
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<AudioMete> Ptr;
|
typedef std::shared_ptr<AudioMeta> Ptr;
|
||||||
|
|
||||||
AudioMete(const AudioTrack::Ptr &audio,int datarate = 160);
|
AudioMeta(const AudioTrack::Ptr &audio,int datarate = 160);
|
||||||
|
|
||||||
virtual ~AudioMete(){}
|
virtual ~AudioMeta(){}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回音频或视频类型
|
* 返回音频或视频类型
|
||||||
|
@ -45,8 +45,8 @@ RtmpDemuxer::RtmpDemuxer(const AMFValue &val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int RtmpDemuxer::getTrackCount(const AMFValue &metedata) {
|
int RtmpDemuxer::getTrackCount(const AMFValue &metadata) {
|
||||||
return (int)(metedata["videocodecid"].type() != AMF_NULL) + (int)(metedata["audiocodecid"].type() != AMF_NULL);
|
return (int)(metadata["videocodecid"].type() != AMF_NULL) + (int)(metadata["audiocodecid"].type() != AMF_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
bool RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||||
|
@ -49,7 +49,7 @@ public:
|
|||||||
RtmpDemuxer(){}
|
RtmpDemuxer(){}
|
||||||
/**
|
/**
|
||||||
* 构造rtmp解复用器
|
* 构造rtmp解复用器
|
||||||
* @param val rtmp的metedata,可以传入null类型,
|
* @param val rtmp的metadata,可以传入null类型,
|
||||||
* 这样就会在inputRtmp时异步探测媒体编码格式
|
* 这样就会在inputRtmp时异步探测媒体编码格式
|
||||||
*/
|
*/
|
||||||
RtmpDemuxer(const AMFValue &val);
|
RtmpDemuxer(const AMFValue &val);
|
||||||
@ -58,10 +58,10 @@ public:
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 获取rtmp track 数
|
* 获取rtmp track 数
|
||||||
* @param metedata rtmp的metedata
|
* @param metadata rtmp的metadata
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int getTrackCount(const AMFValue &metedata);
|
static int getTrackCount(const AMFValue &metadata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始解复用
|
* 开始解复用
|
||||||
|
@ -86,6 +86,9 @@ public:
|
|||||||
virtual void onGetMetaData(const AMFValue &metadata) {
|
virtual void onGetMetaData(const AMFValue &metadata) {
|
||||||
lock_guard<recursive_mutex> lock(_mtxMap);
|
lock_guard<recursive_mutex> lock(_mtxMap);
|
||||||
_metadata = metadata;
|
_metadata = metadata;
|
||||||
|
if(_pRing){
|
||||||
|
regist();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onWrite(const RtmpPacket::Ptr &pkt,bool isKey = true) override {
|
void onWrite(const RtmpPacket::Ptr &pkt,bool isKey = true) override {
|
||||||
@ -107,8 +110,10 @@ public:
|
|||||||
strongSelf->onReaderChanged(size);
|
strongSelf->onReaderChanged(size);
|
||||||
});
|
});
|
||||||
onReaderChanged(0);
|
onReaderChanged(0);
|
||||||
|
if(_metadata){
|
||||||
regist();
|
regist();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_pRing->write(pkt,pkt->isVideoKeyFrame());
|
_pRing->write(pkt,pkt->isVideoKeyFrame());
|
||||||
checkNoneReader();
|
checkNoneReader();
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public:
|
|||||||
RtmpMediaSourceMuxer(const string &vhost,
|
RtmpMediaSourceMuxer(const string &vhost,
|
||||||
const string &strApp,
|
const string &strApp,
|
||||||
const string &strId,
|
const string &strId,
|
||||||
const TitleMete::Ptr &title = nullptr) : RtmpMuxer(title){
|
const TitleMeta::Ptr &title = nullptr) : RtmpMuxer(title){
|
||||||
_mediaSouce = std::make_shared<RtmpMediaSource>(vhost,strApp,strId);
|
_mediaSouce = std::make_shared<RtmpMediaSource>(vhost,strApp,strId);
|
||||||
getRtmpRing()->setDelegate(_mediaSouce);
|
getRtmpRing()->setDelegate(_mediaSouce);
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void onAllTrackReady() override {
|
void onAllTrackReady() override {
|
||||||
_mediaSouce->onGetMetaData(getMetedata());
|
_mediaSouce->onGetMetaData(getMetadata());
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
RtmpMediaSource::Ptr _mediaSouce;
|
RtmpMediaSource::Ptr _mediaSouce;
|
||||||
|
@ -29,11 +29,11 @@
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
RtmpMuxer::RtmpMuxer(const TitleMete::Ptr &title) {
|
RtmpMuxer::RtmpMuxer(const TitleMeta::Ptr &title) {
|
||||||
if(!title){
|
if(!title){
|
||||||
_metedata = std::make_shared<TitleMete>()->getMetedata();
|
_metadata = std::make_shared<TitleMeta>()->getMetadata();
|
||||||
}else{
|
}else{
|
||||||
_metedata = title->getMetedata();
|
_metadata = title->getMetadata();
|
||||||
}
|
}
|
||||||
_rtmpRing = std::make_shared<RtmpRingInterface::RingType>();
|
_rtmpRing = std::make_shared<RtmpRingInterface::RingType>();
|
||||||
}
|
}
|
||||||
@ -45,24 +45,24 @@ void RtmpMuxer::onTrackReady(const Track::Ptr &track) {
|
|||||||
if (!encoder) {
|
if (!encoder) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//根据track生产metedata
|
//根据track生产metadata
|
||||||
Metedata::Ptr metedate;
|
Metadata::Ptr metadata;
|
||||||
switch (track->getTrackType()){
|
switch (track->getTrackType()){
|
||||||
case TrackVideo:{
|
case TrackVideo:{
|
||||||
metedate = std::make_shared<VideoMete>(dynamic_pointer_cast<VideoTrack>(track));
|
metadata = std::make_shared<VideoMeta>(dynamic_pointer_cast<VideoTrack>(track));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TrackAudio:{
|
case TrackAudio:{
|
||||||
metedate = std::make_shared<AudioMete>(dynamic_pointer_cast<AudioTrack>(track));
|
metadata = std::make_shared<AudioMeta>(dynamic_pointer_cast<AudioTrack>(track));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;;
|
return;;
|
||||||
|
|
||||||
}
|
}
|
||||||
//添加其metedata
|
//添加其metadata
|
||||||
metedate->getMetedata().object_for_each([&](const std::string &key, const AMFValue &value){
|
metadata->getMetadata().object_for_each([&](const std::string &key, const AMFValue &value){
|
||||||
_metedata.set(key,value);
|
_metadata.set(key,value);
|
||||||
});
|
});
|
||||||
//设置Track的代理,这样输入frame至Track时,最终数据将输出到RtmpEncoder中
|
//设置Track的代理,这样输入frame至Track时,最终数据将输出到RtmpEncoder中
|
||||||
track->addDelegate(encoder);
|
track->addDelegate(encoder);
|
||||||
@ -71,13 +71,13 @@ void RtmpMuxer::onTrackReady(const Track::Ptr &track) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const AMFValue &RtmpMuxer::getMetedata() const {
|
const AMFValue &RtmpMuxer::getMetadata() const {
|
||||||
if(!isAllTrackReady()){
|
if(!isAllTrackReady()){
|
||||||
//尚未就绪
|
//尚未就绪
|
||||||
static AMFValue s_amf;
|
static AMFValue s_amf;
|
||||||
return s_amf;
|
return s_amf;
|
||||||
}
|
}
|
||||||
return _metedata;
|
return _metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtmpRingInterface::RingType::Ptr RtmpMuxer::getRtmpRing() const {
|
RtmpRingInterface::RingType::Ptr RtmpMuxer::getRtmpRing() const {
|
||||||
|
@ -41,14 +41,14 @@ public:
|
|||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
*/
|
*/
|
||||||
RtmpMuxer(const TitleMete::Ptr &title);
|
RtmpMuxer(const TitleMeta::Ptr &title);
|
||||||
virtual ~RtmpMuxer(){}
|
virtual ~RtmpMuxer(){}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取完整的SDP字符串
|
* 获取完整的SDP字符串
|
||||||
* @return SDP字符串
|
* @return SDP字符串
|
||||||
*/
|
*/
|
||||||
const AMFValue &getMetedata() const ;
|
const AMFValue &getMetadata() const ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取rtmp环形缓存
|
* 获取rtmp环形缓存
|
||||||
@ -64,7 +64,7 @@ protected:
|
|||||||
void onTrackReady(const Track::Ptr & track) override ;
|
void onTrackReady(const Track::Ptr & track) override ;
|
||||||
private:
|
private:
|
||||||
RtmpRingInterface::RingType::Ptr _rtmpRing;
|
RtmpRingInterface::RingType::Ptr _rtmpRing;
|
||||||
AMFValue _metedata;
|
AMFValue _metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ private:
|
|||||||
_pRtmpMediaSrc->onWrite(chunkData);
|
_pRtmpMediaSrc->onWrite(chunkData);
|
||||||
}
|
}
|
||||||
if(!_parser){
|
if(!_parser){
|
||||||
//这个流没有metedata
|
//这个流没有metadata
|
||||||
_parser.reset(new RtmpDemuxer());
|
_parser.reset(new RtmpDemuxer());
|
||||||
}
|
}
|
||||||
_parser->inputRtmp(chunkData);
|
_parser->inputRtmp(chunkData);
|
||||||
|
@ -431,6 +431,7 @@ void RtmpSession::setMetaData(AMFDecoder &dec) {
|
|||||||
}
|
}
|
||||||
auto metadata = dec.load<AMFValue>();
|
auto metadata = dec.load<AMFValue>();
|
||||||
//dumpMetadata(metadata);
|
//dumpMetadata(metadata);
|
||||||
|
_metadata_got = true;
|
||||||
_pPublisherSrc->onGetMetaData(metadata);
|
_pPublisherSrc->onGetMetaData(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,6 +489,11 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
|
|||||||
_stamp[chunkData.typeId % 2].revise(0, 0, dts_out, dts_out);
|
_stamp[chunkData.typeId % 2].revise(0, 0, dts_out, dts_out);
|
||||||
chunkData.timeStamp = dts_out;
|
chunkData.timeStamp = dts_out;
|
||||||
}
|
}
|
||||||
|
if(!_metadata_got){
|
||||||
|
//有些rtmp推流客户端不产生metadata,我们产生一个默认的metadata,目的是为了触发注册操作
|
||||||
|
_metadata_got = true;
|
||||||
|
_pPublisherSrc->onGetMetaData(TitleMeta().getMetadata());
|
||||||
|
}
|
||||||
_pPublisherSrc->onWrite(std::make_shared<RtmpPacket>(std::move(chunkData)));
|
_pPublisherSrc->onWrite(std::make_shared<RtmpPacket>(std::move(chunkData)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -553,7 +559,7 @@ void RtmpSession::setSocketFlags(){
|
|||||||
|
|
||||||
void RtmpSession::dumpMetadata(const AMFValue &metadata) {
|
void RtmpSession::dumpMetadata(const AMFValue &metadata) {
|
||||||
if(metadata.type() != AMF_OBJECT && metadata.type() != AMF_ECMA_ARRAY){
|
if(metadata.type() != AMF_OBJECT && metadata.type() != AMF_ECMA_ARRAY){
|
||||||
WarnL << "invalid metedata type:" << metadata.type();
|
WarnL << "invalid metadata type:" << metadata.type();
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
|
@ -87,8 +87,9 @@ private:
|
|||||||
void onNoneReader(MediaSource &sender) override;
|
void onNoneReader(MediaSource &sender) override;
|
||||||
void setSocketFlags();
|
void setSocketFlags();
|
||||||
string getStreamId(const string &str);
|
string getStreamId(const string &str);
|
||||||
void dumpMetadata(const AMFValue &metedata);
|
void dumpMetadata(const AMFValue &metadata);
|
||||||
private:
|
private:
|
||||||
|
bool _metadata_got = false;
|
||||||
std::string _strTcUrl;
|
std::string _strTcUrl;
|
||||||
MediaInfo _mediaInfo;
|
MediaInfo _mediaInfo;
|
||||||
double _dNowReqID = 0;
|
double _dNowReqID = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user