mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-10-30 16:27:36 +08:00
优化播放器接口
This commit is contained in:
parent
fcfb434cf2
commit
afc36f5ef4
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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() {};
|
||||
|
||||
|
@ -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(), "/");
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -50,7 +50,7 @@ void RtmpPusher::teardown() {
|
||||
m_dqOnStatusCB.clear();
|
||||
}
|
||||
m_pPublishTimer.reset();
|
||||
clear();
|
||||
reset();
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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--;
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user