EasyDarwin流媒体和推流器按需推流的解决方法

本人在一家创业公司工作一年,这里对Easydarwin流媒体的使用有一定的心德,这里写出来跟大家学习,希望大家不要笑话我!!!
我在这个公司最后的工作中,有一个按需推流的需求,开始我对这方面不是很懂,到处问人,在Easydarwin团队的babosa指导,看了他们的解决方案http://blog.csdn.net/ss00_2012/article/details/51441753,奈何需求不一样,未能完全实现。因为我们只用了Easydarwin的一部分东西
之后我老大说可以在rtsp连接握手的时候能进行操作。所以我进行一系列的学习,最终找到了添加的位置。
Eesydarwin的流媒体服务器重 最重要的是 QTSSReflectorModule  这个模块, 触发,EasyDarwin为每一路推流转发维护一个ReflectorSession对象,该对象的fNumOutputs属性用来指示当前拉流客户端的数量。当客户端停止拉流时会调用QTSSReflectorModule::DestroySession()->QTSSReflectorModule::RemoveOutput()->ReflectorSession::RemoveOutput(),其中ReflectorSession::RemoveOutput();
但是我们观察DestroySession() 这个函数;在ReflectorSession 维护的对象中有一个 GetNumOutputs ()函数,得到客户端的连接数,这个连接数ReflectorSession对象自己会维护一个,所以但 GetNumOutputs ()<=1的时候我们就通知推流器停止推流
QTSS_Error DestroySession(QTSS_ClientSessionClosing_Params* inParams)
{
    RTPSessionOutput**  theOutput = NULL;
    ReflectorOutput*    outputPtr = NULL;
    ReflectorSession*   theSession = NULL;
   
    OSMutexLocker locker (sSessionMap->GetMutex());
   
    UInt32 theLen = sizeof(theSession);
    QTSS_Error theErr = QTSS_GetValue(inParams->inClientSession, sClientBroadcastSessionAttr, 0, &theSession, &theLen);
    //qtss_printf("QTSSReflectorModule.cpp:DestroySession    sClientBroadcastSessionAttr=%"_U32BITARG_" theSession=%"_U32BITARG_" err=%"_S32BITARG_" \n",(UInt32)sClientBroadcastSessionAttr, (UInt32)theSession,theErr);
    if (theSession != NULL) // 这里是推流器
    {  
        ReflectorSession*   deletedSession = NULL;
        theErr = QTSS_SetValue(inParams->inClientSession, sClientBroadcastSessionAttr, 0, &deletedSession, sizeof(deletedSession));
 
        SourceInfo* theSoureInfo = theSession->GetSourceInfo();
        if (theSoureInfo == NULL)
            return QTSS_NoErr;
           
        UInt32  numStreams = theSession->GetNumStreams();
        SourceInfo::StreamInfo* theStreamInfo = NULL;
           
        for (UInt32 index = 0; index < numStreams; index++)
        {   theStreamInfo = theSoureInfo->GetStreamInfo(index);
            if (theStreamInfo != NULL)
                theStreamInfo->fSetupToReceive = false;
        }
 
        Bool16 killClients = false; // the pref as the default
        UInt32 theLen = sizeof(killClients);
        (void) QTSS_GetValue(inParams->inClientSession, sKillClientsEnabledAttr, 0, &killClients, &theLen);
 
       
        //qtss_printf("QTSSReflectorModule.cpp:DestroySession broadcaster theSession=%"_U32BITARG_"\n", (UInt32) theSession);
        theSession->RemoveSessionFromOutput(inParams->inClientSession);
 
           if(sHLSOutputEnabled)
                 theSession->StopHLSSession();
        printf("---停止推流----\n");
        RemoveOutput(NULL, theSession, killClients);
    }
    else//这里是客户端
    {
        theLen = 0;
        theErr = QTSS_GetValuePtr(inParams->inClientSession, sOutputAttr, 0, (void**)&theOutput, &theLen);
        if ((theErr != QTSS_NoErr) || (theLen != sizeof(RTPSessionOutput*)) || (theOutput == NULL) || (*theOutput == NULL))
            return QTSS_RequestFailed;
        theSession = (*theOutput)->GetReflectorSession();
       
        int num= theSession->GetNumOutputs();
        printf("theSession->GetNumOutputs()-----:%d\n",theSession->GetNumOutputs());
      
          //判断引用数是否为0.
        if(num<=1)
        {
                 
            QTSServerInterface::GetServer()->CastToCenterServerPushStram(theSession->GetSessionName(),1);            
           // theSession->RemoveSessionFromOutput(theSession);  
           
        }
     
       
        if (theOutput != NULL)
            outputPtr = (ReflectorOutput*) *theOutput;
           
        if (outputPtr != NULL)
        {   
            RemoveOutput(outputPtr, theSession, false);
            RTPSessionOutput* theOutput = NULL;
            (void)QTSS_SetValue(inParams->inClientSession, sOutputAttr, 0, &theOutput, sizeof(theOutput));           
        }
       
               
    }
 
    return QTSS_NoErr;
}

当播放器播放一串rtsp地址就是向流媒体请求,rtsp 的握手就开始了
enum
{
    qtssDescribeMethod      = 0,
    qtssSetupMethod         = 1,
    qtssTeardownMethod      = 2,
    qtssNumVIPMethods       = 3,
 
    qtssPlayMethod          = 3,
    qtssPauseMethod         = 4,
    qtssOptionsMethod       = 5,
    qtssAnnounceMethod      = 6,
    qtssGetParameterMethod  = 7,
    qtssSetParameterMethod  = 8,
    qtssRedirectMethod      = 9,
    qtssRecordMethod        = 10,
   
    qtssNumMethods          = 11,
    qtssIllegalMethod       = 11
   
};
typedef UInt32 QTSS_RTSPMethod;  
这是表示连接状态的枚举,而播放器发送给流媒体
流媒体进行恢复ProcessRTSPRequest ()->DoDescribe();
播放器发送给流媒体服务器的都是一个theFilepath
./movies/9800010.sdp 所以通过设备代码我们就能找到设备
所以我们就能在DoDescribe ();这个函数里发信息给推流器,让推流开启推流
QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams)
{
char *theFilepath = NULL;
ReflectorSession* theSession = DoSessionSetup(inParams, qtssRTSPReqFilePath, false, NULL, &theFilepath );
OSCharArrayDeleter tempFilePath(theFilepath);

//通知中服务器推流
QTSServerInterface::GetServer()->CastToCenterServerPushStram(theFilepath,0);

if (theSession == NULL)
return QTSS_RequestFailed;
....
return QTSS_NoErr;
}


由于我们没有使用Easydarwin的网络模块,是自己一个udp网络库 要在QTSServerInterface.h这里添加自己网络管理模块回调
//函数指针
typedef void(*OnCastCenterServerPushStream)(void* mediaMng, char* sdpName,int type);

class QTSServerInterface : public QTSSDictionary
{
public:
//Initialize must be called right off the bat to initialize dictionary resources
static void Initialize();
//
// CONSTRUCTOR / DESTRUCTOR
QTSServerInterface();
virtual ~QTSServerInterface() {}
//通知中心服务器进行推流操作
virtual void CastToCenterServerPushStram(char* steamName,int type){}


public:
//流媒体管理句柄
void* mediaManager;
//通知回调
OnCastCenterServerPushStream CallFunc;
};


而QTSServer这和模块继承了QTSServerInterface ,所以我们要把我们加的方法实现

class QTSServer : public QTSServerInterface
{
public:

QTSServer()
{
}
virtual ~QTSServer();

//
// Initialize
//
// This function starts the server. If it returns true, the server has
// started up sucessfully. If it returns false, a fatal error occurred
// while attempting to start the server.
//
// This function *must* be called before the server creates any threads,
// because one of its actions is to change the server to the right UID / GID.
// Threads will only inherit these if they are created afterwards.
Bool16 Initialize(XMLPrefsParser* inPrefsSource, PrefsSource* inMessagesSource,
UInt16 inPortOverride, Bool16 createListeners,const char*inAbsolutePath);
//
// InitModules
//
// Initialize *does not* do much of the module initialization tasks. This
// function may be called after the server has created threads, but the
// server must not be in a state where it can do real work. In other words,
// call this function right after calling Initialize.
void InitModules(QTSS_ServerState inEndState);
//通知中心服务进行推流关流操作
void CastToCenterServerPushStram(char* steamName,int type);
........................................................
};

//实现让中心服务器推流操作
void QTSServer::CastToCenterServerPushStram(char* steamName,int type){
//设置0为请求推流播放 1为请求推流播放停止
if(mediaManager!=0 && CallFunc!=0){
CallFunc(mediaManager,steamName,type);
}
}


上面的想通了,后面主要是这个数据的回调问题,我开始是自己写的一个数据传输的类,但是在这里面编译不过了,因为Easydarwin里面重构new,最后终于知道用回调。这个按需推流是很low,因为并不是我要播放的时候就马上推流,可以你第一次播放rtsp 才向流媒体申请,流媒体才发送信息给推流器让推流器推流。所以想过并不理想,但是功能是有的。
thanks Easydarwin,还有流媒体大神云上鱼的指点。



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值