优化播放器接口

This commit is contained in:
xiongziliang 2017-08-03 13:55:46 +08:00
parent fcfb434cf2
commit afc36f5ef4
15 changed files with 98 additions and 66 deletions

View File

@ -18,21 +18,16 @@ using namespace ZL::Thread;
namespace ZL {
namespace DEV {
const char PlayerProxy::kAliveSecond[] = "alive_second";
PlayerProxy::PlayerProxy(const char *strApp,const char *strSrc){
m_strApp = strApp;
m_strSrc = strSrc;
}
void PlayerProxy::play(const char* strUrl, const char *strUser,
const char *strPwd, PlayerBase::eRtpType eType, uint32_t iSecond) {
m_aliveSecond = iSecond;
string strUrlTmp(strUrl);
string strUserTmp(strUser);
string strPwdTmp(strPwd);
m_pPlayer.reset(new MediaPlayer());
void PlayerProxy::play(const char* strUrl) {
m_aliveSecond = (*this)[kAliveSecond];
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
m_pPlayer->setOnVideoCB( [weakSelf,strUrlTmp](const H264Frame &data ) {
setOnVideoCB( [weakSelf](const H264Frame &data ) {
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
@ -44,7 +39,7 @@ void PlayerProxy::play(const char* strUrl, const char *strUser,
}
strongSelf->checkExpired();
});
m_pPlayer->setOnAudioCB( [weakSelf,strUrlTmp](const AdtsFrame &data ) {
setOnAudioCB( [weakSelf](const AdtsFrame &data ) {
auto strongSelf = weakSelf.lock();
if(!strongSelf){
return;
@ -58,7 +53,8 @@ void PlayerProxy::play(const char* strUrl, const char *strUser,
});
std::shared_ptr<uint64_t> piFailedCnt(new uint64_t(0)); //连续播放失败次数
m_pPlayer->setOnPlayResult([weakSelf,strUrlTmp,strUserTmp,strPwdTmp,eType,piFailedCnt](const SockException &err) {
string strUrlTmp(strUrl);
setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
@ -69,13 +65,12 @@ void PlayerProxy::play(const char* strUrl, const char *strUser,
*piFailedCnt = 0;//连续播放失败次数清0
}else if(*piFailedCnt < replayCnt) {
// 播放失败,延时重试播放
strongSelf->rePlay(strUrlTmp, strUserTmp, strPwdTmp, eType,(*piFailedCnt)++);
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}else{
strongSelf->expired();
}
});
weak_ptr<MediaPlayer> weakPtr= m_pPlayer;
m_pPlayer->setOnShutdown([weakSelf,weakPtr,strUrlTmp,strUserTmp,strPwdTmp,eType,piFailedCnt](const SockException &err) {
setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
@ -86,52 +81,52 @@ void PlayerProxy::play(const char* strUrl, const char *strUser,
//播放异常中断,延时重试播放
static uint64_t replayCnt = mINI::Instance()[Config::Proxy::kReplayCount].as<uint64_t>();
if(*piFailedCnt < replayCnt) {
strongSelf->rePlay(strUrlTmp, strUserTmp, strPwdTmp, eType,(*piFailedCnt)++);
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}else{
strongSelf->expired();
}
});
m_pPlayer->play(strUrl, strUser, strPwd, eType);
MediaPlayer::play(strUrl);
}
PlayerProxy::~PlayerProxy() {
auto iTaskId = reinterpret_cast<uint64_t>(this);
AsyncTaskThread::Instance().CancelTask(iTaskId);
}
void PlayerProxy::rePlay(const string &strUrl, const string &strUser, const string &strPwd, PlayerBase::eRtpType eType, uint64_t iFailedCnt){
void PlayerProxy::rePlay(const string &strUrl,uint64_t iFailedCnt){
checkExpired();
auto iTaskId = reinterpret_cast<uint64_t>(this);
auto iDelay = MAX((uint64_t)2 * 1000, MIN(iFailedCnt * 3000,(uint64_t)60*1000));
weak_ptr<MediaPlayer> weakPtr = m_pPlayer;
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
AsyncTaskThread::Instance().CancelTask(iTaskId);
AsyncTaskThread::Instance().DoTaskDelay(iTaskId, iDelay, [weakPtr,strUrl,strUser,strPwd,eType,iFailedCnt]() {
AsyncTaskThread::Instance().DoTaskDelay(iTaskId, iDelay, [weakSelf,strUrl,iFailedCnt]() {
//播放失败次数越多,则延时越长
auto strongPlayer = weakPtr.lock();
auto strongPlayer = weakSelf.lock();
if(!strongPlayer) {
return false;
}
WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl;
strongPlayer->play(strUrl.data(), strUser.data(), strPwd.data(), eType);
strongPlayer->MediaPlayer::play(strUrl.data());
return false;
});
}
void PlayerProxy::initMedia() {
if (!m_pPlayer->isInited()) {
if (!isInited()) {
return;
}
m_pChn.reset(new DevChannel(m_strApp.data(),m_strSrc.data(),m_pPlayer->getDuration()));
if (m_pPlayer->containVideo()) {
m_pChn.reset(new DevChannel(m_strApp.data(),m_strSrc.data(),getDuration()));
if (containVideo()) {
VideoInfo info;
info.iFrameRate = m_pPlayer->getVideoFps();
info.iWidth = m_pPlayer->getVideoWidth();
info.iHeight = m_pPlayer->getVideoHeight();
info.iFrameRate = getVideoFps();
info.iWidth = getVideoWidth();
info.iHeight = getVideoHeight();
m_pChn->initVideo(info);
}
if (m_pPlayer->containAudio()) {
if (containAudio()) {
AudioInfo info;
info.iSampleRate = m_pPlayer->getAudioSampleRate();
info.iChannel = m_pPlayer->getAudioChannel();
info.iSampleBit = m_pPlayer->getAudioSampleBit();
info.iSampleRate = getAudioSampleRate();
info.iChannel = getAudioChannel();
info.iSampleBit = getAudioSampleBit();
m_pChn->initAudio(info);
}
}

View File

@ -19,17 +19,20 @@ using namespace ZL::Player;
namespace ZL {
namespace DEV {
class PlayerProxy : public std::enable_shared_from_this<PlayerProxy>{
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 *strApp, const char *strSrc);
void play(const char* strUrl, const char *strUser = "", const char *strPwd = "",PlayerBase::eRtpType eType = PlayerBase::RTP_TCP,uint32_t iSecond = 0);
virtual ~PlayerProxy();
void play(const char* strUrl) override;
void setOnExpired(const function<void()> &cb){
onExpired = cb;
}
private :
MediaPlayer::Ptr m_pPlayer;
DevChannel::Ptr m_pChn;
Ticker m_aliveTicker;
uint32_t m_aliveSecond = 0;
@ -37,7 +40,7 @@ private :
string m_strApp;
string m_strSrc;
void initMedia();
void rePlay(const string &strUrl, const string &strUser, const string &strPwd, PlayerBase::eRtpType eType,uint64_t iFailedCnt);
void rePlay(const string &strUrl,uint64_t iFailedCnt);
void checkExpired();
void expired();
};

View File

@ -22,8 +22,7 @@ MediaPlayer::MediaPlayer() {
MediaPlayer::~MediaPlayer() {
teardown();
}
void MediaPlayer::play(const char* strUrl, const char* strUser, const char* strPwd, eRtpType eType) {
void MediaPlayer::play(const char* strUrl) {
string strPrefix = FindField(strUrl, NULL, "://");
if ((strcasecmp(m_strPrefix.data(),strPrefix.data()) != 0) || strPrefix.empty()) {
//协议切换
@ -34,9 +33,11 @@ void MediaPlayer::play(const char* strUrl, const char* strUser, const char* strP
m_parser->setOnAudioCB(m_onGetAudioCB);
}
m_parser->setOnPlayResult(m_playResultCB);
m_parser->play(strUrl, strUser, strPwd, eType);
m_parser->mINI::operator=(*this);
m_parser->play(strUrl);
}
void MediaPlayer::pause(bool bPause) {
if (m_parser) {
m_parser->pause(bPause);

View File

@ -12,8 +12,12 @@
#include <string>
#include "Player.h"
#include "PlayerBase.h"
#include "Rtsp/RtspPlayer.h"
#include "Rtmp/RtmpPlayer.h"
using namespace std;
using namespace ZL::Rtsp;
using namespace ZL::Rtmp;
namespace ZL {
namespace Player {
@ -24,8 +28,7 @@ public:
MediaPlayer();
virtual ~MediaPlayer();
void play(const char* strUrl, const char *strUser = "", const char *strPwd = "", eRtpType eType = RTP_TCP) override;
void play(const char* strUrl) override;
void pause(bool bPause) override;
void teardown() override;
private:

View File

@ -8,19 +8,22 @@
#ifndef SRC_PLAYER_PLAYERBASE_H_
#define SRC_PLAYER_PLAYERBASE_H_
#include <map>
#include <memory>
#include <string>
#include <functional>
#include "Player.h"
#include "Network/Socket.h"
#include "Util/mini.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Network;
namespace ZL {
namespace Player {
class PlayerBase{
class PlayerBase : public mINI{
public:
typedef std::shared_ptr<PlayerBase> Ptr;
typedef enum {
@ -32,8 +35,7 @@ public:
PlayerBase(){};
virtual ~PlayerBase(){};
virtual void play(const char* strUrl, const char *strUser = "", const char *strPwd = "", eRtpType eType = RTP_TCP) {};
virtual void play(const char* strUrl) {};
virtual void pause(bool bPause) {};
virtual void teardown() {};

View File

@ -52,12 +52,12 @@ void RtmpPlayer::teardown() {
m_fSeekTo = 0;
CLEAR_ARR(m_adFistStamp);
CLEAR_ARR(m_adNowStamp);
clear();
reset();
shutdown();
}
}
void RtmpPlayer::play(const char* strUrl, const char * , const char *, eRtpType) {
void RtmpPlayer::play(const char* strUrl) {
teardown();
string strHost = FindField(strUrl, "://", "/");
m_strApp = FindField(strUrl, (strHost + "/").data(), "/");

View File

@ -36,8 +36,7 @@ public:
RtmpPlayer();
virtual ~RtmpPlayer();
void play(const char* strUrl, const char *strUser, const char *strPwd,
eRtpType eType) override;
void play(const char* strUrl) override;
void pause(bool bPause) override;
void teardown() override;
protected:

View File

@ -48,9 +48,9 @@ RtmpProtocol::RtmpProtocol() {
};
}
RtmpProtocol::~RtmpProtocol() {
clear();
reset();
}
void RtmpProtocol::clear() {
void RtmpProtocol::reset() {
////////////ChunkSize////////////
m_iChunkLenIn = DEFAULT_CHUNK_LEN;
m_iChunkLenOut = DEFAULT_CHUNK_LEN;

View File

@ -33,7 +33,7 @@ public:
//作为客户端发送c0c1等待s0s1s2并且回调
void startClientSession(const function<void()> &cb);
void onParseRtmp(const char *pcRawData,int iSize);
void clear();
void reset();
protected:
virtual void onSendRawData(const char *pcRawData,int iSize) = 0;
virtual void onRtmpChunk(RtmpPacket &chunkData) = 0;

View File

@ -50,7 +50,7 @@ void RtmpPusher::teardown() {
m_dqOnStatusCB.clear();
}
m_pPublishTimer.reset();
clear();
reset();
shutdown();
}
}

View File

@ -22,6 +22,8 @@ namespace Rtsp {
_onRecvRTP(it->second, trackidx); \
m_amapRtpSort[trackidx].erase(it);
const char RtspPlayer::kRtpType[] = "rtp_type";
RtspPlayer::RtspPlayer(void){
}
RtspPlayer::~RtspPlayer(void) {
@ -67,13 +69,34 @@ void RtspPlayer::teardown(){
shutdown();
}
}
void RtspPlayer::play(const char* strUrl){
auto userAndPwd = FindField(strUrl,"://","@");
eRtpType eType = (eRtpType)(int)(*this)[kRtpType];
if(userAndPwd.empty()){
play(strUrl,nullptr,nullptr,eType);
return;
}
auto suffix = FindField(strUrl,"@",nullptr);
auto url = StrPrinter << "rtsp://" << suffix << endl;
if(userAndPwd.find(":") == string::npos){
play(url.data(),userAndPwd.data(),nullptr,eType);
return;
}
auto user = FindField(userAndPwd.data(),nullptr,":");
auto pwd = FindField(userAndPwd.data(),":",nullptr);
play(url.data(),user.data(),pwd.data(),eType);
}
//播放指定是否走rtp over tcp
void RtspPlayer::play(const char* strUrl, const char *strUser, const char *strPwd, eRtpType eType ) {
InfoL <<strUrl <<" "<< eType;
DebugL << strUrl << " "
<< (strUser ? strUser : "null") << " "
<< (strPwd ? strPwd:"null") << " "
<< eType;
teardown();
if(strUser && strPwd){
if(strUser){
char _authorization[30];
string tmp = StrPrinter << strUser << ":" << strPwd << endl;
string tmp = StrPrinter << strUser << ":" << (strPwd ? strPwd : "") << endl;
av_base64_encode(_authorization, sizeof(_authorization), (const unsigned char *) tmp.c_str(), tmp.size());
m_strAuthorization = _authorization;
}

View File

@ -36,9 +36,13 @@ namespace Rtsp {
class RtspPlayer: public PlayerBase,public TcpClient {
public:
typedef std::shared_ptr<RtspPlayer> Ptr;
//设置rtp传输类型可选项有0(tcp默认)、1(udp)、2(组播)
//设置方法player[RtspPlayer::kRtpType] = 0/1/2;
static const char kRtpType[];
RtspPlayer();
virtual ~RtspPlayer(void);
void play(const char* strUrl, const char *strUser, const char *strPwd, eRtpType eType) override;
void play(const char* strUrl) override;
void pause(bool bPause) override;
void teardown() override;
float getRtpLossRate(int iTrackId) const override;
@ -84,6 +88,7 @@ private:
onPlayResult(ex);
}
void play(const char* strUrl, const char *strUser, const char *strPwd, eRtpType eType);
void onConnect(const SockException &err) override;
void onRecv(const Socket::Buffer::Ptr &pBuf) override;
void onErr(const SockException &ex) override;

View File

@ -52,7 +52,8 @@ int main(int argc, char *argv[]){
player->setOnShutdown([&](const SockException &ex){
--alivePlayerCnt;
});
player->play(argv[3], "", "", (PlayerBase::eRtpType)atoi(argv[4]));
(*player)[RtspPlayer::kRtpType] = atoi(argv[4]);
player->play(argv[3]);
playerList.push_back(player);
return playerCnt--;
});

View File

@ -5,8 +5,8 @@
#include <iostream>
#include "Poller/EventPoller.h"
#include "Rtsp/UDPServer.h"
#include "Player/MediaPlayer.h"
#include "Util/onceToken.h"
#include "Device/PlayerProxy.h"
#include "H264Decoder.h"
#include "YuvDisplayer.h"
#include "Network/sockutil.h"
@ -18,7 +18,7 @@ using namespace ZL::Util;
using namespace ZL::Thread;
using namespace ZL::Network;
using namespace ZL::Rtsp;
using namespace ZL::DEV;
using namespace ZL::Player;
void programExit(int arg) {
EventPoller::Instance().shutdown();
@ -30,9 +30,9 @@ int main(int argc, char *argv[]){
//Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
signal(SIGINT, programExit);
if(argc != 5){
FatalL << "\r\n测试方法:./test_player rtxp_url rtsp_user rtsp_pwd rtp_type\r\n"
<< "例如:./test_player rtsp://127.0.0.1/live/0 admin 123456 0\r\n"
if(argc != 3){
FatalL << "\r\n测试方法:./test_player rtxp_url rtp_type\r\n"
<< "例如:./test_player rtsp://admin:123456@127.0.0.1/live/0 0\r\n"
<<endl;
Logger::Destory();
return 0;
@ -46,9 +46,8 @@ int main(int argc, char *argv[]){
player->setOnShutdown([](const SockException &ex) {
ErrorL << "OnShutdown:" << ex.what();
});
//DebugL << argv[1] << " " << argv[2] << " " << argv[3] << " " << argv[4] << endl;
player->play(argv[1],argv[2],argv[3],(PlayerBase::eRtpType)atoi(argv[4]));
(*player)[RtspPlayer::kRtpType] = atoi(argv[2]);
player->play(argv[1]);
H264Decoder decoder;
YuvDisplayer displayer;

View File

@ -49,7 +49,7 @@ int main(int argc,char *argv[]){
//support rtmp and rtsp url
//just support H264+AAC
auto urlList = {"rtmp://live.hkstv.hk.lxdns.com/live/hks",
"rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov"};
"rtsp://admin:jzan123456@192.168.0.122/"};
map<string , PlayerProxy::Ptr> proxyMap;
int i=0;
for(auto url : urlList){
@ -63,6 +63,7 @@ int main(int argc,char *argv[]){
//rtsp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
//rtmp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
PlayerProxy::Ptr player(new PlayerProxy("live",to_string(i++).data()));
(*player)[PlayerProxy::kAliveSecond] = 10;//录制10秒
player->play(url);
proxyMap.emplace(string(url),player);
}