#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(); }