添加Rtmp推流示例

This commit is contained in:
xiongziliang 2017-06-06 20:06:31 +08:00
parent f3fe820234
commit 568d8ad53f
5 changed files with 107 additions and 22 deletions

BIN
src/.DS_Store vendored

Binary file not shown.

View File

@ -49,7 +49,7 @@ void RtmpPusher::teardown() {
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB); lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
m_dqOnStatusCB.clear(); m_dqOnStatusCB.clear();
} }
m_pPlayTimer.reset(); m_pPublishTimer.reset();
clear(); clear();
shutdown(); shutdown();
} }
@ -63,7 +63,7 @@ void RtmpPusher::publish(const char* strUrl) {
m_strTcUrl = string("rtmp://") + strHost + "/" + m_strApp; m_strTcUrl = string("rtmp://") + strHost + "/" + m_strApp;
if (!m_strApp.size() || !m_strStream.size()) { if (!m_strApp.size() || !m_strStream.size()) {
_onPlayResult(SockException(Err_other,"rtmp url非法")); onPublishResult(SockException(Err_other,"rtmp url非法"));
return; return;
} }
DebugL << strHost << " " << m_strApp << " " << m_strStream; DebugL << strHost << " " << m_strApp << " " << m_strStream;
@ -80,20 +80,20 @@ void RtmpPusher::publish(const char* strUrl) {
} }
void RtmpPusher::onErr(const SockException &ex){ void RtmpPusher::onErr(const SockException &ex){
_onShutdown(ex); onShutdown(ex);
} }
void RtmpPusher::onConnect(const SockException &err){ void RtmpPusher::onConnect(const SockException &err){
if(err.getErrCode()!=Err_success) { if(err.getErrCode()!=Err_success) {
_onPlayResult(err); onPublishResult(err);
return; return;
} }
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
m_pPlayTimer.reset( new Timer(10, [weakSelf]() { m_pPublishTimer.reset( new Timer(10, [weakSelf]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
strongSelf->_onPlayResult(SockException(Err_timeout,"publish rtmp timeout")); strongSelf->onPublishResult(SockException(Err_timeout,"publish rtmp timeout"));
strongSelf->teardown(); strongSelf->teardown();
return false; return false;
})); }));
@ -111,8 +111,8 @@ void RtmpPusher::onRecv(const Socket::Buffer::Ptr &pBuf){
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(pBuf->data(), pBuf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
_onPlayResult(ex); onPublishResult(ex);
_onShutdown(ex); onShutdown(ex);
teardown(); teardown();
} }
} }
@ -193,11 +193,11 @@ inline void RtmpPusher::send_metaData(){
m_pRtmpReader->setDetachCB([weakSelf](){ m_pRtmpReader->setDetachCB([weakSelf](){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(strongSelf){ if(strongSelf){
strongSelf->_onShutdown(SockException(Err_other,"媒体源被释放")); strongSelf->onShutdown(SockException(Err_other,"媒体源被释放"));
strongSelf->teardown(); strongSelf->teardown();
} }
}); });
_onPlayResult(SockException(Err_success,"success")); onPublishResult(SockException(Err_success,"success"));
} }
void RtmpPusher::onCmd_result(AMFDecoder &dec){ void RtmpPusher::onCmd_result(AMFDecoder &dec){
auto iReqId = dec.load<int>(); auto iReqId = dec.load<int>();

View File

@ -18,12 +18,21 @@ namespace Rtmp {
class RtmpPusher: public RtmpProtocol , public TcpClient{ class RtmpPusher: public RtmpProtocol , public TcpClient{
public: public:
typedef std::shared_ptr<RtmpPusher> Ptr; typedef std::shared_ptr<RtmpPusher> Ptr;
typedef std::function<void(const SockException &ex)> Event;
RtmpPusher(const char *strApp,const char *strStream); RtmpPusher(const char *strApp,const char *strStream);
virtual ~RtmpPusher(); virtual ~RtmpPusher();
void publish(const char* strUrl); void publish(const char* strUrl);
void teardown(); void teardown();
void setOnPublished(Event onPublished) {
m_onPublished = onPublished;
}
void setOnShutdown(Event onShutdown) {
m_onShutdown = onShutdown;
}
protected: protected:
//for Tcpclient //for Tcpclient
@ -36,19 +45,18 @@ protected:
void onSendRawData(const char *pcRawData, int iSize) override { void onSendRawData(const char *pcRawData, int iSize) override {
send(pcRawData, iSize); send(pcRawData, iSize);
} }
virtual void onShutdown(const SockException &ex){}
virtual void onPlayResult(const SockException &ex) {}
private: private:
void _onShutdown(const SockException &ex) { void onShutdown(const SockException &ex) {
WarnL << ex.getErrCode() << " " << ex.what(); m_pPublishTimer.reset();
m_pPlayTimer.reset(); if(m_onShutdown){
onShutdown(ex); m_onShutdown(ex);
}
} }
void _onPlayResult(const SockException &ex) { void onPublishResult(const SockException &ex) {
WarnL << ex.getErrCode() << " " << ex.what(); m_pPublishTimer.reset();
m_pPlayTimer.reset(); if(m_onPublished){
onPlayResult(ex); m_onPublished(ex);
}
} }
template<typename FUN> template<typename FUN>
@ -84,11 +92,14 @@ private:
static unordered_map<string, rtmpCMDHandle> g_mapCmd; static unordered_map<string, rtmpCMDHandle> g_mapCmd;
//超时功能实现 //超时功能实现
std::shared_ptr<Timer> m_pPlayTimer; std::shared_ptr<Timer> m_pPublishTimer;
//源 //源
std::weak_ptr<RtmpMediaSource> m_pMediaSrc; std::weak_ptr<RtmpMediaSource> m_pMediaSrc;
RtmpMediaSource::RingType::RingReader::Ptr m_pRtmpReader; RtmpMediaSource::RingType::RingReader::Ptr m_pRtmpReader;
//事件监听
Event m_onShutdown;
Event m_onPublished;
}; };
} /* namespace Rtmp */ } /* namespace Rtmp */

BIN
tests/.DS_Store vendored Normal file

Binary file not shown.

74
tests/test_rtmpPusher.cpp Normal file
View File

@ -0,0 +1,74 @@
//============================================================================
// Name : main.cpp
// Author : 熊子良
// Version :
//============================================================================
#include <signal.h>
#include <unistd.h>
#include <iostream>
#include "Util/logger.h"
#include "Util/onceToken.h"
#include "Util/NoticeCenter.h"
#include "Poller/EventPoller.h"
#include "Device/PlayerProxy.h"
#include "Rtmp/RtmpPusher.h"
#include "Common/config.h"
using namespace std;
using namespace ZL::Util;
using namespace ZL::Rtmp;
using namespace ZL::Thread;
using namespace ZL::Network;
using namespace ZL::DEV;
void programExit(int arg) {
EventPoller::Instance().shutdown();
}
int main(int argc,char *argv[]){
setExePath(argv[0]);
signal(SIGINT, programExit);
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
PlayerProxy::Ptr player(new PlayerProxy("app","stream"));
//拉一个流生成一个RtmpMediaSource源的名称是"app/stream"
//你也可以以其他方式生成RtmpMediaSource比如说MP4文件请研读MediaReader代码
player->play("rtmp://live.hkstv.hk.lxdns.com/live/hks");
RtmpPusher::Ptr pusher;
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发。
NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastRtmpSrcRegisted,
[&pusher](BroadcastRtmpSrcRegistedArgs){
//媒体源"app/stream"已经注册这时方可新建一个RtmpPusher对象并绑定该媒体源
const_cast<RtmpPusher::Ptr &>(pusher).reset(new RtmpPusher(app,stream));
pusher->setOnPublished([](const SockException &ex){
if(ex){
WarnL << "发布失败:" << ex.what();
}else{
InfoL << "发布成功请用播放器打开rtmp://jizan.iok.la/live/test";
}
});
//推流地址,请改成你自己的服务器。
//这个范例地址也是基于mediakit是可用的但是带宽只有1mb访问可能很卡顿。
pusher->publish("rtmp://jizan.iok.la/live/test");
//如果你想监听RtmpPusher的相关事件请派生之并重载 onShutdown 与 onPlayResult方法
});
EventPoller::Instance().runLoop();
NoticeCenter::Instance().delListener(nullptr);
player.reset();
pusher.reset();
EventPoller::Destory();
Logger::Destory();
return 0;
}