#include "playCommon.h"
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"
#include <assert.h>
//--------------------------------------------------
Boolean sendOptionsRequest = TRUE;
Boolean sendOptionsRequestOnly = False;
portNumBits tunnelOverHTTPPortNum = 0;
Authenticator* ourAuthenticator = NULL;
//--------------------------------------------------
void continueAfterOPTIONS(RTSPClient* client, int resultCode, char* resultString);
void continueAfterDESCRIBE(RTSPClient* client, int resultCode, char* resultString);
void continueAfterSETUP(RTSPClient* client, int resultCode, char* resultString);
void continueAfterPLAY(RTSPClient* client, int resultCode, char* resultString);
void continueAfterTEARDOWN(RTSPClient* client, int resultCode, char* resultString);
void subsessionAfterPlaying(void* clientData);
void subsessionByeHandler(void* clientData);
void sessionAfterPlaying();
void setupStreams();
void failFun();
void StopRtsp();
void close_rtsp();
void teardownRTSPorSIPSession();
//--------------------------------------------------
typedef struct openrtsp_t
{
openrtsp_t()
{
scheduler = NULL;
env = NULL;
rtspClient = NULL;
session = NULL;
duration = 0;
durationSlop = -1.0;
initialSeekTime = 0.0f;
scale = 1.0f;
endTime = 0;
setupIter = NULL;
}
TaskScheduler* scheduler;
UsageEnvironment* env;
RTSPClient* rtspClient;
MediaSession* session;
MediaSubsessionIterator* setupIter;
unsigned short desiredPortNum;
double duration;
double durationSlop; // extra seconds to play at the end
double initialSeekTime;
float scale;
double endTime;
HANDLE hThread;
}openrtsp_t;
openrtsp_t g_openrtsp;
void Init()
{
g_openrtsp.scheduler = BasicTaskScheduler::createNew();
g_openrtsp.env = BasicUsageEnvironment::createNew(*g_openrtsp.scheduler);
}
void UnInit()
{
StopRtsp();
}
DWORD rtspThread(LPVOID lp)
{
g_openrtsp.env->taskScheduler().doEventLoop(); // does not return
return 0;
}
int ConnServer(char* strUrl)
{
g_openrtsp.rtspClient = (RTSPClient *)createClient(*g_openrtsp.env, strUrl, 1, "openrtsp.exe");
if (g_openrtsp.rtspClient == NULL) {
return false;
}
if (sendOptionsRequest) {
// Begin by sending an "OPTIONS" command:
getOptions(continueAfterOPTIONS);
} else {
continueAfterOPTIONS(NULL, 0, NULL);
}
// All subsequent activity takes place within the event loop:
g_openrtsp.hThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)rtspThread,NULL,0/*CREATE_SUSPENDED*/,0);
return true;
}
void rtsp_data_deal(unsigned char *,unsigned int)
{
}
void failFun()
{
g_openrtsp.scheduler->StopEventLoop();
}
//void getOptions(RTSPClient::responseHandler* afterFunc) {
// g_openrtsp.rtspClient->sendOptionsCommand(afterFunc, ourAuthenticator);
//}
//
//Medium* createClient(UsageEnvironment& env, char const* url, int verbosityLevel, char const* applicationName) {
// extern portNumBits tunnelOverHTTPPortNum;
// return ourRTSPClient = RTSPClient::createNew(env, url, verbosityLevel, applicationName, tunnelOverHTTPPortNum);
//}
void continueAfterPLAY(RTSPClient*, int resultCode, char* resultString) {
if (resultCode != 0) {
failFun();
return;
}
/*
if (qosMeasurementIntervalMS > 0) {
// Begin periodic QOS measurements:
beginQOSMeasurement();
}
// Figure out how long to delay (if at all) before shutting down, or
// repeating the playing
Boolean timerIsBeingUsed = False;
double secondsToDelay = duration;
if (duration > 0) {
timerIsBeingUsed = True;
double absScale = scale > 0 ? scale : -scale; // ASSERT: scale != 0
secondsToDelay = duration/absScale + durationSlop;
int64_t uSecsToDelay = (int64_t)(secondsToDelay*1000000.0);
sessionTimerTask = env->taskScheduler().scheduleDelayedTask(uSecsToDelay, (TaskFunc*)sessionTimerHandler, (void*)NULL);
}
char const* actionString
= createReceivers? "Receiving streamed data":"Data is being streamed";
if (timerIsBeingUsed) {
*env << actionString
<< " (for up to " << secondsToDelay
<< " seconds)...\n";
} else {
#ifdef USE_SIGNALS
pid_t ourPid = getpid();
*env << actionString
<< " (signal with \"kill -HUP " << (int)ourPid
<< "\" or \"kill -USR1 " << (int)ourPid
<< "\" to terminate)...\n";
#else
*env << actionString << "...\n";
#endif
}
// Watch for incoming packets (if desired):
checkForPacketArrival(NULL);
checkInterPacketGaps(NULL);
*/
}
void continueAfterSETUP(RTSPClient*, int resultCode, char* resultString) {
if (resultCode != 0) {
failFun();
return;
}
// Set up the next subsession, if any:
setupStreams();
}
void continueAfterOPTIONS(RTSPClient*, int resultCode, char* resultString) {
if (sendOptionsRequestOnly)
{
if (resultString)
{
delete[] resultString;
}
if (resultCode != 0) {
failFun();
}
return;
}
if (resultString)
{
delete[] resultString;
}
// Next, get a SDP description for the stream:
getSDPDescription(continueAfterDESCRIBE);
}
void continueAfterDESCRIBE(RTSPClient*, int resultCode, char* resultString)
{
if (resultCode != 0) {
failFun();
return;
}
char* sdpDescription = resultString;
// Create a media session object from this SDP description:
g_openrtsp.session = MediaSession::createNew(*g_openrtsp.env, sdpDescription);
delete[] sdpDescription;
if (g_openrtsp.session == NULL) {
failFun();
return;
} else if (!g_openrtsp.session->hasSubsessions()) {
failFun();
return;
}
// Then, setup the "RTPSource"s for the session:
MediaSubsessionIterator iter(*g_openrtsp.session);
MediaSubsession *subsession;
Boolean madeProgress = False;
char const* singleMediumToTest = "xxxxx";
while ((subsession = iter.next()) != NULL) {
if (g_openrtsp.desiredPortNum != 0) {
subsession->setClientPortNum(g_openrtsp.desiredPortNum);
g_openrtsp.desiredPortNum += 2;
}
if (!subsession->initiate(-1)) {
} else {
madeProgress = True;
if (subsession->rtpSource() != NULL) {
// Because we're saving the incoming data, rather than playing
// it in real time, allow an especially large time threshold
// (1 second) for reordering misordered incoming packets:
unsigned const thresh = 1000000; // 1 second
subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
// Set the RTP source's OS socket buffer size as appropriate - either if we were explicitly asked (using -B),
// or if the desired FileSink buffer size happens to be larger than the current OS socket buffer size.
// (The latter case is a heuristic, on the assumption that if the user asked for a large FileSink buffer size,
// then the input data rate may be large enough to justify increasing the OS socket buffer size also.)
int socketNum = subsession->rtpSource()->RTPgs()->socketNum();
unsigned curBufferSize = getReceiveBufferSize(*g_openrtsp.env, socketNum);
}
}
}
// Perform additional 'setup' on each subsession, before playing them:
setupStreams();
}
void setupStreams()
{
MediaSubsession *subsession = NULL;
Boolean madeProgress = False;
Boolean streamUsingTCP = TRUE;
if (g_openrtsp.setupIter == NULL)
g_openrtsp.setupIter = new MediaSubsessionIterator(*g_openrtsp.session);
while ((subsession = g_openrtsp.setupIter->next()) != NULL) {
// We have another subsession left to set up:
if (subsession->clientPortNum() == 0) continue; // port # was not set
setupSubsession(subsession, streamUsingTCP, continueAfterSETUP);
return;
}
// We're done setting up subsessions.
delete g_openrtsp.setupIter;
g_openrtsp.setupIter = NULL;
// Create output files:
{
// Create and start "FileSink"s for each subsession:
madeProgress = False;
MediaSubsessionIterator iter(*g_openrtsp.session);
while ((subsession = iter.next()) != NULL)
{
if (subsession->readSource() == NULL)
continue; // was not initiated
// Create an output file for each desired stream:
FileSink* fileSink;
if (strcmp(subsession->mediumName(), "audio") == 0 &&
(strcmp(subsession->codecName(), "AMR") == 0 ||
strcmp(subsession->codecName(), "AMR-WB") == 0)) {
assert(0 == 1);
// For AMR audio streams, we use a special sink that inserts AMR frame hdrs:
/*fileSink = AMRAudioFileSink::createNew(*env, outFileName,
fileSinkBufferSize, oneFilePerFrame);*/
} else if (strcmp(subsession->mediumName(), "video") == 0 &&
(strcmp(subsession->codecName(), "H264") == 0)) {
// For H.264 video stream, we use a special sink that insert start_codes:
//fileSink = H264VideoFileSink::createNew(*env, outFileName,
// fileSinkBufferSize, oneFilePerFrame);
// For H.264 video stream, we use a special sink that insert start_codes:
unsigned int num=0;
SPropRecord * sps=parseSPropParameterSets(subsession->fmtp_spropparametersets(),num);
fileSink = H264VideoFileSink::createNew(*g_openrtsp.env, "d:\h264"/*outFileName*/, //\\storage card\\h264\\SDMMC
0, false);
struct timeval tv={0,0};
unsigned char buf[4] = {0};
unsigned int len = 0;
unsigned char start_code[4] = {0x00, 0x00, 0x00, 0x01};
buf[0] = 27;
fileSink->addData(buf,1,tv);
memset(buf,0,4);
fileSink->addData(buf,4,tv);
len = sps[0].sPropLength + 4;
memcpy(buf,&len,4);
fileSink->addData(buf,4,tv);
fileSink->addData(start_code, 4, tv);
fileSink->addData(sps[0].sPropBytes,sps[0].sPropLength,tv);
buf[0] = 27;
fileSink->addData(buf,1,tv);
memset(buf,0,4);
fileSink->addData(buf,4,tv);
len = sps[1].sPropLength + 4;
memcpy(buf,&len,4);
fileSink->addData(buf,4,tv);
fileSink->addData(start_code, 4, tv);
fileSink->addData(sps[1].sPropBytes,sps[1].sPropLength,tv);
delete[] sps;
} else {
// Normal case:
fileSink = FileSink::createNew(*g_openrtsp.env, "d:\\vod"/*outFileName*/,//\\storage card\\video-H264-2\\SDMMC\\video-H264-2
0, false);
}
subsession->sink = fileSink;
if (strcmp(subsession->mediumName(), "video") == 0 &&
strcmp(subsession->codecName(), "MP4V-ES") == 0 &&
subsession->fmtp_config() != NULL)
{
// For MPEG-4 video RTP streams, the 'config' information
// from the SDP description contains useful VOL etc. headers.
// Insert this data at the front of the output file:
unsigned configLen;
unsigned char* configData
= parseGeneralConfigStr(subsession->fmtp_config(), configLen);
struct timeval timeNow;
gettimeofday(&timeNow, NULL);
fileSink->addData(configData, configLen, timeNow);
delete[] configData;
}
subsession->sink->startPlaying(*(subsession->readSource()),
subsessionAfterPlaying,
subsession);
// Also set a handler to be called if a RTCP "BYE" arrives
// for this subsession:
if (subsession->rtcpInstance() != NULL) {
subsession->rtcpInstance()->setByeHandler(subsessionByeHandler,
subsession);
}
madeProgress = True;
}
}
// Finally, start playing each subsession, to start the data flow:
if (g_openrtsp.duration == 0) {
if (g_openrtsp.scale > 0) g_openrtsp.duration = g_openrtsp.session->playEndTime() - 0; // use SDP end time
else if (g_openrtsp.scale < 0) g_openrtsp.duration = 0;
}
if (g_openrtsp.duration < 0) g_openrtsp.duration = 0.0;
g_openrtsp.endTime = g_openrtsp.initialSeekTime;
if (g_openrtsp.scale > 0) {
if (g_openrtsp.duration <= 0) g_openrtsp.endTime = -1.0f;
else g_openrtsp.endTime = g_openrtsp.initialSeekTime + g_openrtsp.duration;
} else {
g_openrtsp.endTime = g_openrtsp.initialSeekTime - g_openrtsp.duration;
if (g_openrtsp.endTime < 0) g_openrtsp.endTime = 0.0f;
}
startPlayingSession(g_openrtsp.session, g_openrtsp.initialSeekTime, g_openrtsp.endTime, g_openrtsp.scale, continueAfterPLAY);
}
void subsessionAfterPlaying(void* clientData) {
// Begin by closing this media subsession's stream:
MediaSubsession* subsession = (MediaSubsession*)clientData;
Medium::close(subsession->sink);
subsession->sink = NULL;
// Next, check whether *all* subsessions' streams have now been closed:
MediaSession& session = subsession->parentSession();
MediaSubsessionIterator iter(session);
while ((subsession = iter.next()) != NULL) {
if (subsession->sink != NULL) return; // this subsession is still active
}
// All subsessions' streams have now been closed
sessionAfterPlaying();
}
void subsessionByeHandler(void* clientData) {
struct timeval timeNow;
gettimeofday(&timeNow, NULL);
//unsigned secsDiff = timeNow.tv_sec - startTime.tv_sec;
MediaSubsession* subsession = (MediaSubsession*)clientData;
// Act now as if the subsession had closed:
subsessionAfterPlaying(subsession);
}
void sessionAfterPlaying() {
// We've been asked to play the stream(s) over again:
startPlayingSession(g_openrtsp.session, g_openrtsp.initialSeekTime, g_openrtsp.endTime, g_openrtsp.scale, continueAfterPLAY);
}
void StopRtsp()
{
TerminateThread(g_openrtsp.hThread,0);
if (g_openrtsp.rtspClient != NULL && g_openrtsp.session) {
MediaSubsessionIterator iter(*(g_openrtsp.session));
MediaSubsession* subsession;
while ((subsession = iter.next()) != NULL) {
Medium::close(subsession->sink);
subsession->sink = NULL;
g_openrtsp.rtspClient->sendTeardownCommand(*subsession,NULL,NULL);
}
}
UsageEnvironment* env = NULL;
TaskScheduler* scheduler = NULL;
if (g_openrtsp.session != NULL) {
env = &(g_openrtsp.session->envir());
scheduler = &(env->taskScheduler());
}
Medium::close(g_openrtsp.session);
// Medium::close(g_openrtsp.rtspClient);
delete g_openrtsp.rtspClient;
g_openrtsp.rtspClient = NULL;
g_openrtsp.session = NULL;
g_openrtsp.env->reclaim();
if (g_openrtsp.env)
{
delete g_openrtsp.env;
g_openrtsp.env = NULL;
}
if (g_openrtsp.scheduler)
{
delete g_openrtsp.scheduler;
g_openrtsp.scheduler = NULL;
}
if (g_openrtsp.setupIter)
{
delete g_openrtsp.setupIter;
g_openrtsp.setupIter = NULL;
}
}
void close_rtsp()
{
teardownRTSPorSIPSession();
UsageEnvironment* env = NULL;
TaskScheduler* scheduler = NULL;
if (g_openrtsp.session != NULL) {
env = &(g_openrtsp.session->envir());
scheduler = &(env->taskScheduler());
}
Medium::close(g_openrtsp.session);
Medium::close(g_openrtsp.rtspClient);
env->reclaim();
delete scheduler;
}
void teardownRTSPorSIPSession()
{
MediaSession* mediaSession = g_openrtsp.session;
if (mediaSession == NULL) return;
if (g_openrtsp.rtspClient != NULL) {
MediaSubsessionIterator iter(*mediaSession);
MediaSubsession* subsession;
while ((subsession = iter.next()) != NULL) {
g_openrtsp.rtspClient->teardownMediaSubsession(*subsession);
}
}
}
ez:
extern "C" void Init();
extern "C" int ConnServer(char* strUrl);
extern "C" void UnInit();
void CRtspDownPCDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
//OnOK();
Init();
ConnServer("rtsp://119.4.250.56:80/rtplive/kbws.sdp");
}
void CRtspDownPCDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
UnInit();
}
转自 http://hi.baidu.com/cr0_3/blog/item/7310afdd3b71595995ee3735.html