修改文件录制、hls生成、拉流代理逻辑

This commit is contained in:
xiongziliang 2018-02-07 11:16:43 +08:00
parent ae1b62c78f
commit 5ed2ce40fe
14 changed files with 160 additions and 133 deletions

View File

@ -29,10 +29,6 @@
#include "Util/onceToken.h"
#include "Network/sockutil.h"
#ifndef UINT64_MAX
#define UINT64_MAX 0xFFFFFFFFFFFFFFFF
#endif//UINT64_MAX
using namespace ZL::Network;
namespace Config {
@ -61,20 +57,6 @@ onceToken token([](){
},nullptr);
} //namespace Broadcast
//代理失败最大重试次数
namespace Proxy {
#define PROXY_FIELD "proxy."
#define PROXY_REPLAY_CNT (UINT64_MAX)
const char kReplayCount[] = PROXY_FIELD"replayCount";
onceToken token([](){
mINI::Instance()[kReplayCount] = PROXY_REPLAY_CNT;
},nullptr);
}//namespace Proxy
////////////HTTP配置///////////
namespace Http {
#define HTTP_FIELD "http."

View File

@ -104,12 +104,6 @@ extern const char kBroadcastFlowReport[];
extern const char kFlowThreshold[];
} //namespace Broadcast
//代理失败最大重试次数
namespace Proxy {
extern const char kReplayCount[];
}//namespace Proxy
////////////HTTP配置///////////
namespace Http {
extern const char kPort[];

View File

@ -36,8 +36,13 @@ using namespace ZL::Util;
namespace ZL {
namespace DEV {
DevChannel::DevChannel(const char *strVhost,const char *strApp, const char *strId,float fDuration,bool bLiveStream ) :
RtspToRtmpMediaSource(strVhost,strApp,strId , bLiveStream) {
DevChannel::DevChannel(const char *strVhost,
const char *strApp,
const char *strId,
float fDuration,
bool bEanbleHls,
bool bEnableMp4 ) :
RtspToRtmpMediaSource(strVhost,strApp,strId,bEanbleHls,bEnableMp4) {
m_strSdp = "v=0\r\n";
m_strSdp += "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n";
@ -46,7 +51,7 @@ DevChannel::DevChannel(const char *strVhost,const char *strApp, const char *strI
m_strSdp += "c=IN IP4 0.0.0.0\r\n";
m_strSdp += "t=0 0\r\n";
//直播,时间长度永远
if(fDuration <= 0 || bLiveStream){
if(fDuration <= 0){
m_strSdp += "a=range:npt=0-\r\n";
}else{
m_strSdp += StrPrinter <<"a=range:npt=0-" << fDuration << "\r\n" << endl;
@ -56,9 +61,9 @@ DevChannel::DevChannel(const char *strVhost,const char *strApp, const char *strI
DevChannel::~DevChannel() {
}
#ifdef ENABLE_X264
void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) {
//TimeTicker1(50);
#ifdef ENABLE_X264
if (!m_pH264Enc) {
m_pH264Enc.reset(new H264Encoder());
if (!m_pH264Enc->init(m_video->iWidth, m_video->iHeight, m_video->iFrameRate)) {
@ -73,13 +78,11 @@ void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) {
inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp);
}
}
#else
ErrorL << "libx264 was not enabled!";
#endif //ENABLE_X264
}
#endif //ENABLE_X264
void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
#ifdef ENABLE_FAAC
void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
if (!m_pAacEnc) {
m_pAacEnc.reset(new AACEncoder());
if (!m_pAacEnc->init(m_audio->iSampleRate, m_audio->iChannel, m_audio->iSampleBit)) {
@ -94,10 +97,8 @@ void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
inputAAC((char *) pucOut, iRet, uiStamp);
}
}
#else
ErrorL << "libfaac was not enabled!";
#endif //ENABLE_FAAC
}
#endif //ENABLE_FAAC
void DevChannel::inputH264(char* pcData, int iDataLen, uint32_t uiStamp) {
if (!m_pRtpMaker_h264) {

View File

@ -69,18 +69,30 @@ public:
class DevChannel : public RtspToRtmpMediaSource{
public:
typedef std::shared_ptr<DevChannel> Ptr;
DevChannel(const char *strVhost,const char *strApp, const char *strId,float fDuration = 0,bool bLiveStream = true);
//fDuration<=0为直播否则为点播
DevChannel(const char *strVhost,
const char *strApp,
const char *strId,
float fDuration = 0,
bool bEanbleHls = true,
bool bEnableMp4 = false);
virtual ~DevChannel();
void initVideo(const VideoInfo &info);
void initAudio(const AudioInfo &info);
void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp);
void inputPCM(char *pcData, int iDataLen, uint32_t uiStamp);
void inputH264(char *pcData, int iDataLen, uint32_t uiStamp);
void inputAAC(char *pcDataWithAdts, int iDataLen, uint32_t uiStamp);
void inputAAC(char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,char *pcAdtsHeader);
#ifdef ENABLE_X264
void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp);
#endif //ENABLE_X264
#ifdef ENABLE_FAAC
void inputPCM(char *pcData, int iDataLen, uint32_t uiStamp);
#endif //ENABLE_FAAC
private:
inline void makeSDP_264(unsigned char *pucData, int iDataLen);
inline void makeSDP_AAC(unsigned char *pucData);

View File

@ -37,15 +37,20 @@ using namespace ZL::Thread;
namespace ZL {
namespace DEV {
const char PlayerProxy::kAliveSecond[] = "alive_second";
PlayerProxy::PlayerProxy(const char *strVhost,const char *strApp,const char *strSrc){
PlayerProxy::PlayerProxy(const char *strVhost,
const char *strApp,
const char *strSrc,
bool bEnableHls,
bool bEnableMp4,
int iRetryCount){
m_strVhost = strVhost;
m_strApp = strApp;
m_strSrc = strSrc;
m_bEnableHls = bEnableHls;
m_bEnableMp4 = bEnableMp4;
m_iRetryCount = iRetryCount;
}
void PlayerProxy::play(const char* strUrl) {
m_aliveSecond = (*this)[kAliveSecond];
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
setOnVideoCB( [weakSelf](const H264Frame &data ) {
auto strongSelf = weakSelf.lock();
@ -57,7 +62,6 @@ void PlayerProxy::play(const char* strUrl) {
}else{
strongSelf->initMedia();
}
strongSelf->checkExpired();
});
setOnAudioCB( [weakSelf](const AdtsFrame &data ) {
auto strongSelf = weakSelf.lock();
@ -69,25 +73,21 @@ void PlayerProxy::play(const char* strUrl) {
}else{
strongSelf->initMedia();
}
strongSelf->checkExpired();
});
std::shared_ptr<uint64_t> piFailedCnt(new uint64_t(0)); //连续播放失败次数
std::shared_ptr<int> piFailedCnt(new int(0)); //连续播放失败次数
string strUrlTmp(strUrl);
setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
static uint64_t replayCnt = mINI::Instance()[Config::Proxy::kReplayCount].as<uint64_t>();
if(!err) {
// 播放成功
*piFailedCnt = 0;//连续播放失败次数清0
}else if(*piFailedCnt < replayCnt) {
}else if(*piFailedCnt < strongSelf->m_iRetryCount || strongSelf->m_iRetryCount < 0) {
// 播放失败,延时重试播放
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}else{
strongSelf->expired();
}
});
setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
@ -99,11 +99,8 @@ void PlayerProxy::play(const char* strUrl) {
strongSelf->m_pChn.reset();
}
//播放异常中断,延时重试播放
static uint64_t replayCnt = mINI::Instance()[Config::Proxy::kReplayCount].as<uint64_t>();
if(*piFailedCnt < replayCnt) {
if(*piFailedCnt < strongSelf->m_iRetryCount || strongSelf->m_iRetryCount < 0) {
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}else{
strongSelf->expired();
}
});
MediaPlayer::play(strUrl);
@ -113,10 +110,9 @@ PlayerProxy::~PlayerProxy() {
auto iTaskId = reinterpret_cast<uint64_t>(this);
AsyncTaskThread::Instance().CancelTask(iTaskId);
}
void PlayerProxy::rePlay(const string &strUrl,uint64_t iFailedCnt){
checkExpired();
void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){
auto iTaskId = reinterpret_cast<uint64_t>(this);
auto iDelay = MAX((uint64_t)2 * 1000, MIN(iFailedCnt * 3000,(uint64_t)60*1000));
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000,60*1000));
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
AsyncTaskThread::Instance().CancelTask(iTaskId);
AsyncTaskThread::Instance().DoTaskDelay(iTaskId, iDelay, [weakSelf,strUrl,iFailedCnt]() {
@ -134,7 +130,7 @@ void PlayerProxy::initMedia() {
if (!isInited()) {
return;
}
m_pChn.reset(new DevChannel(m_strVhost.data(),m_strApp.data(),m_strSrc.data(),getDuration()));
m_pChn.reset(new DevChannel(m_strVhost.data(),m_strApp.data(),m_strSrc.data(),getDuration(),m_bEnableHls,m_bEnableMp4));
if (containVideo()) {
VideoInfo info;
info.iFrameRate = getVideoFps();
@ -151,18 +147,6 @@ void PlayerProxy::initMedia() {
}
}
void PlayerProxy::checkExpired() {
if(m_aliveSecond && m_aliveTicker.elapsedTime() > m_aliveSecond * 1000){
//到期
expired();
}
}
void PlayerProxy::expired() {
if(onExpired){
onExpired();
}
}
} /* namespace Player */
} /* namespace ZL */

View File

@ -41,28 +41,31 @@ namespace DEV {
class PlayerProxy :public MediaPlayer, public std::enable_shared_from_this<PlayerProxy>{
public:
typedef std::shared_ptr<PlayerProxy> Ptr;
//设置代理时间0为永久其他为代理秒数
//设置方法proxy[PlayerProxy::kAliveSecond] = 100;
static const char kAliveSecond[];
PlayerProxy(const char *strVhost, const char *strApp, const char *strSrc);
//如果iRetryCount<0,则一直重试播放否则重试iRetryCount次数
//默认一直重试
PlayerProxy(const char *strVhost,
const char *strApp,
const char *strSrc,
bool bEnableHls = true,
bool bEnableMp4 = false,
int iRetryCount = -1);
virtual ~PlayerProxy();
void play(const char* strUrl) override;
void setOnExpired(const function<void()> &cb){
onExpired = cb;
}
private:
bool m_bEnableHls;
bool m_bEnableMp4;
int m_iRetryCount;
DevChannel::Ptr m_pChn;
Ticker m_aliveTicker;
uint32_t m_aliveSecond = 0;
function<void()> onExpired;
string m_strVhost;
string m_strApp;
string m_strSrc;
private:
void initMedia();
void rePlay(const string &strUrl,uint64_t iFailedCnt);
void checkExpired();
void expired();
void rePlay(const string &strUrl,int iFailedCnt);
};
} /* namespace Player */

View File

@ -129,7 +129,7 @@ MediaReader::MediaReader(const string &strVhost,const string &strApp, const stri
}
m_iDuration = MAX(m_video_ms,m_audio_ms);
m_pChn.reset(new DevChannel(strVhost.data(),strApp.data(),strId.data(),m_iDuration/1000.0,false));
m_pChn.reset(new DevChannel(strVhost.data(),strApp.data(),strId.data(),m_iDuration/1000.0,true, false));
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
AudioInfo info;
info.iChannel = m_audio_num_channels;

View File

@ -37,7 +37,13 @@ using namespace ZL::Network;
namespace ZL {
namespace MediaFile {
MediaRecorder::MediaRecorder(const string &strVhost ,const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer) {
MediaRecorder::MediaRecorder(const string &strVhost_tmp,
const string &strApp,
const string &strId,
const std::shared_ptr<PlayerBase> &pPlayer,
bool enableHls,
bool enableMp4) {
static string hlsPrefix = mINI::Instance()[Config::Hls::kHttpPrefix];
static string hlsPrefixDefaultVhost = mINI::Instance()[Config::Hls::kHttpPrefixDefaultVhost];
static string hlsPath = mINI::Instance()[Config::Hls::kFilePath];
@ -45,10 +51,17 @@ MediaRecorder::MediaRecorder(const string &strVhost ,const string &strApp,const
static uint32_t hlsDuration = mINI::Instance()[Config::Hls::kSegmentDuration].as<uint32_t>();
static uint32_t hlsNum = mINI::Instance()[Config::Hls::kSegmentNum].as<uint32_t>();
string strVhost = strVhost_tmp;
if(trim(strVhost).empty()){
//如果strVhost为空则强制为默认虚拟主机
strVhost = DEFAULT_VHOST;
}
if(enableHls) {
string hlsPrefixVhost = hlsPrefix;
do {
//生成hls http前缀
if (strVhost.empty() || strVhost == DEFAULT_VHOST) {
if (strVhost == DEFAULT_VHOST) {
hlsPrefixVhost = hlsPrefixDefaultVhost;
break;
}
@ -65,11 +78,14 @@ MediaRecorder::MediaRecorder(const string &strVhost ,const string &strApp,const
m_hlsMaker.reset(new HLSMaker(hlsPath + "/" + strVhost + "/" + strApp + "/" + strId + "/hls.m3u8",
hlsPrefixVhost + "/" + strApp + "/" + strId + "/",
hlsBufSize, hlsDuration, hlsNum));
}
#ifdef ENABLE_MP4V2
static string recordPath = mINI::Instance()[Config::Record::kFilePath];
static string recordAppName = mINI::Instance()[Config::Record::kAppName];
if(enableMp4){
m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/",
strVhost,strApp,strId,pPlayer));
}
#endif //ENABLE_MP4V2
}
@ -77,16 +93,24 @@ MediaRecorder::~MediaRecorder() {
}
void MediaRecorder::inputH264(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType) {
if(m_hlsMaker){
m_hlsMaker->inputH264(pData, ui32Length, ui32TimeStamp * 90, iType);
}
#ifdef ENABLE_MP4V2
if(m_mp4Maker){
m_mp4Maker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
}
#endif //ENABLE_MP4V2
}
void MediaRecorder::inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
if(m_hlsMaker){
m_hlsMaker->inputAAC(pData, ui32Length, ui32TimeStamp * 90);
}
#ifdef ENABLE_MP4V2
if(m_mp4Maker){
m_mp4Maker->inputAAC(pData, ui32Length, ui32TimeStamp);
}
#endif //ENABLE_MP4V2
}

View File

@ -46,7 +46,12 @@ namespace MediaFile {
class MediaRecorder {
public:
typedef std::shared_ptr<MediaRecorder> Ptr;
MediaRecorder(const string &strVhost,const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer);
MediaRecorder(const string &strVhost,
const string &strApp,
const string &strId,
const std::shared_ptr<PlayerBase> &pPlayer,
bool m_enableHls = true,
bool m_enableMp4 = false);
virtual ~MediaRecorder();
void inputH264( void *pData,

View File

@ -36,8 +36,12 @@ using namespace ZL::Network;
namespace ZL {
namespace Rtmp {
RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &vhost,const string &app, const string &id) :
RtmpMediaSource(vhost,app,id) {
RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &vhost,
const string &app,
const string &id,
bool bEnableHls,
bool bEnableMp4) :
RtmpMediaSource(vhost,app,id),m_bEnableHls(bEnableHls),m_bEnableMp4(bEnableMp4) {
}
RtmpToRtspMediaSource::~RtmpToRtspMediaSource() {}
@ -56,14 +60,18 @@ bool RtmpToRtspMediaSource::unregist() {
}
void RtmpToRtspMediaSource::onGetH264(const H264Frame &frame) {
if(m_pRecorder){
m_pRecorder->inputH264((char *) frame.data.data(), frame.data.size(), frame.timeStamp, frame.type);
}
if(m_pRtpMaker_h264){
m_pRtpMaker_h264->makeRtp(frame.data.data() + 4, frame.data.size() - 4, frame.timeStamp);
}
}
inline void RtmpToRtspMediaSource::onGetAdts(const AdtsFrame &frame) {
if(m_pRecorder){
m_pRecorder->inputAAC((char *) frame.data, frame.aac_frame_length, frame.timeStamp);
}
if (m_pRtpMaker_aac) {
m_pRtpMaker_aac->makeRtp((char *) frame.data + 7, frame.aac_frame_length - 7, frame.timeStamp);

View File

@ -56,7 +56,11 @@ class RtmpToRtspMediaSource: public RtmpMediaSource {
public:
typedef std::shared_ptr<RtmpToRtspMediaSource> Ptr;
RtmpToRtspMediaSource(const string &vhost,const string &app, const string &id);
RtmpToRtspMediaSource(const string &vhost,
const string &app,
const string &id,
bool bEnableHls = true,
bool bEnableMp4 = false);
virtual ~RtmpToRtspMediaSource();
bool regist() override;
@ -65,7 +69,7 @@ public:
void onGetMetaData(const AMFValue &_metadata) override {
try {
m_pParser.reset(new RtmpParser(_metadata));
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser));
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser,m_bEnableHls,m_bEnableMp4));
m_pParser->setOnAudioCB(std::bind(&RtmpToRtspMediaSource::onGetAdts, this, placeholders::_1));
m_pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1));
} catch (exception &ex) {
@ -90,7 +94,8 @@ private:
RtpMaker_AAC::Ptr m_pRtpMaker_aac;
RtpMaker_H264::Ptr m_pRtpMaker_h264;
MediaRecorder::Ptr m_pRecorder;
bool m_bEnableHls;
bool m_bEnableMp4;
void onGetH264(const H264Frame &frame);
void onGetAdts(const AdtsFrame &frame);
void makeSDP();

View File

@ -38,8 +38,12 @@ namespace ZL {
namespace Rtsp {
RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &vhost,const string &app,const string &id,bool bEnableFile) :
RtspMediaSource(vhost,app,id),m_bEnableFile(bEnableFile) {
RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &vhost,
const string &app,
const string &id,
bool bEnableHls,
bool bEnableMp4) :
RtspMediaSource(vhost,app,id),m_bEnableHls(bEnableHls),m_bEnableMp4(bEnableMp4) {
}
RtspToRtmpMediaSource::~RtspToRtmpMediaSource() {

View File

@ -41,15 +41,19 @@ namespace Rtsp {
class RtspToRtmpMediaSource: public RtspMediaSource {
public:
typedef std::shared_ptr<RtspToRtmpMediaSource> Ptr;
RtspToRtmpMediaSource(const string &vhost,const string &app,const string &id,bool bEnableFile = true);
RtspToRtmpMediaSource(const string &vhost,
const string &app,
const string &id,
bool bEnableHls = true,
bool bEnableMp4 = true);
virtual ~RtspToRtmpMediaSource();
virtual void onGetSDP(const string& strSdp) override{
try {
m_pParser.reset(new RtpParser(strSdp));
if(m_bEnableFile){
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser));
}
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser,m_bEnableHls,m_bEnableMp4));
m_pParser->setOnAudioCB( std::bind(&RtspToRtmpMediaSource::onGetAdts, this, placeholders::_1));
m_pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1));
makeMetaData();
@ -92,7 +96,8 @@ private:
RtmpMediaSource::Ptr m_pRtmpSrc;
uint8_t m_ui8AudioFlags = 0;
MediaRecorder::Ptr m_pRecorder;
bool m_bEnableFile = true;
bool m_bEnableHls;
bool m_bEnableMp4;
void onGetH264(const H264Frame &frame);
void onGetAdts(const AdtsFrame &frame);
void makeVideoConfigPkt();

View File

@ -112,16 +112,16 @@ static onceToken s_token([](){
NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastRtmpPublish,[](BroadcastRtmpPublishArgs){
InfoL << args.m_vhost << " " << args.m_app << " " << args.m_streamid << " " << args.m_param_strs ;
EventPoller::Instance().async([invoker](){
//invoker(true,"");//鉴权成功
invoker(false,"this is auth failed message");//鉴权失败
//invoker("");//鉴权成功
invoker("this is auth failed message");//鉴权失败
});
});
NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastMediaPlayed,[](BroadcastMediaPlayedArgs){
InfoL << args.m_schema << " " << args.m_vhost << " " << args.m_app << " " << args.m_streamid << " " << args.m_param_strs ;
EventPoller::Instance().async([invoker](){
//invoker(true,"");//鉴权成功
invoker(false,"this is auth failed message");//鉴权失败
//invoker("");//鉴权成功
invoker("this is auth failed message");//鉴权失败
});
});