live555

来源:互联网 发布:linux设置共享目录 编辑:程序博客网 时间:2024/05/01 09:41

1、DynamicRTSPServer.cpp

ServerMediaSession* DynamicRTSPServer::lookupServerMediaSession(char const* streamName, Boolean isFirstLookupInSession) {  // First, check whether the specified "streamName" exists as a local file:  // Next, check whether we already have a "ServerMediaSession" for this file:  ServerMediaSession* sms = RTSPServer::lookupServerMediaSession(streamName);  Boolean smsExists = sms != NULL;   FILE* fid = fopen(streamName, "rb");  Boolean fileExists = fid != NULL;    if(strcmp(streamName,"live") == 0)  {if (smsExists) {  // "sms" was created for a file that no longer exists. Remove it:  removeServerMediaSession(sms);  sms = NULL;}if (sms == NULL) {  sms = createNewSMS(envir(), streamName, fid);   addServerMediaSession(sms);}return sms;     }    // Handle the four possibilities for "fileExists" and "smsExists":  if (!fileExists) {    if (smsExists) {      // "sms" was created for a file that no longer exists. Remove it:      removeServerMediaSession(sms);      sms = NULL;    }    return NULL;  } else {    if (smsExists && isFirstLookupInSession) {       // Remove the existing "ServerMediaSession" and create a new one, in case the underlying      // file has changed in some way:      removeServerMediaSession(sms);       sms = NULL;    }     if (sms == NULL) {      sms = createNewSMS(envir(), streamName, fid);       addServerMediaSession(sms);    }    fclose(fid);    return sms;  }}
static ServerMediaSession* createNewSMS(UsageEnvironment& env,char const* fileName, FILE* /*fid*/) {  ServerMediaSession* sms = NULL;  Boolean const reuseSource = False;  if (strcmp(fileName, "live") == 0) {    NEW_SMS("live");    //env << "live detected. addsubsession:\n";    //sms->addSubsession(LiveADTSAudioServerMediaSubsession::createNew(env, fileName, reuseSource));    OutPacketBuffer::maxSize = 300000;     sms->addSubsession(LiveVideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));    return sms;  }     // Use the file name extension to determine the type of "ServerMediaSession":  char const* extension = strrchr(fileName, '.');  if (extension == NULL) return NULL;  if (strcmp(extension, ".aac") == 0) {    // Assumed to be an AAC Audio (ADTS format) file:    NEW_SMS("AAC Audio");    sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".amr") == 0) {    // Assumed to be an AMR Audio file:    NEW_SMS("AMR Audio");    sms->addSubsession(AMRAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".ac3") == 0) {    // Assumed to be an AC-3 Audio file:    NEW_SMS("AC-3 Audio");    sms->addSubsession(AC3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".m4e") == 0) {    // Assumed to be a MPEG-4 Video Elementary Stream file:    NEW_SMS("MPEG-4 Video");    sms->addSubsession(MPEG4VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".264") == 0) {    // Assumed to be a H.264 Video Elementary Stream file:    NEW_SMS("H.264 Video");    OutPacketBuffer::maxSize = 300000; // allow for some possibly large H.264 frames    sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".265") == 0) {    // Assumed to be a H.265 Video Elementary Stream file:    NEW_SMS("H.265 Video");    OutPacketBuffer::maxSize = 300000; // allow for some possibly large H.265 frames    sms->addSubsession(H265VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".mp3") == 0) {    // Assumed to be a MPEG-1 or 2 Audio file:    NEW_SMS("MPEG-1 or 2 Audio");    // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following://#define STREAM_USING_ADUS 1    // To also reorder ADUs before streaming, uncomment the following://#define INTERLEAVE_ADUS 1    // (For more information about ADUs and interleaving,    //  see <http://www.live555.com/rtp-mp3/>)    Boolean useADUs = False;    Interleaving* interleaving = NULL;#ifdef STREAM_USING_ADUS    useADUs = True;#ifdef INTERLEAVE_ADUS    unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...    unsigned const interleaveCycleSize      = (sizeof interleaveCycle)/(sizeof (unsigned char));    interleaving = new Interleaving(interleaveCycleSize, interleaveCycle);#endif#endif    sms->addSubsession(MP3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, useADUs, interleaving));  } else if (strcmp(extension, ".mpg") == 0) {    // Assumed to be a MPEG-1 or 2 Program Stream (audio+video) file:    NEW_SMS("MPEG-1 or 2 Program Stream");    MPEG1or2FileServerDemux* demux      = MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);    sms->addSubsession(demux->newVideoServerMediaSubsession());    sms->addSubsession(demux->newAudioServerMediaSubsession());  } else if (strcmp(extension, ".vob") == 0) {    // Assumed to be a VOB (MPEG-2 Program Stream, with AC-3 audio) file:    NEW_SMS("VOB (MPEG-2 video with AC-3 audio)");    MPEG1or2FileServerDemux* demux      = MPEG1or2FileServerDemux::createNew(env, fileName, reuseSource);    sms->addSubsession(demux->newVideoServerMediaSubsession());    sms->addSubsession(demux->newAC3AudioServerMediaSubsession());  } else if (strcmp(extension, ".ts") == 0) {    // Assumed to be a MPEG Transport Stream file:    // Use an index file name that's the same as the TS file name, except with ".tsx":    unsigned indexFileNameLen = strlen(fileName) + 2; // allow for trailing "x\0"    char* indexFileName = new char[indexFileNameLen];    sprintf(indexFileName, "%sx", fileName);    NEW_SMS("MPEG Transport Stream");    sms->addSubsession(MPEG2TransportFileServerMediaSubsession::createNew(env, fileName, indexFileName, reuseSource));    delete[] indexFileName;  } else if (strcmp(extension, ".wav") == 0) {    // Assumed to be a WAV Audio file:    NEW_SMS("WAV Audio Stream");    // To convert 16-bit PCM data to 8-bit u-law, prior to streaming,    // change the following to True:    Boolean convertToULaw = False;    sms->addSubsession(WAVAudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, convertToULaw));  } else if (strcmp(extension, ".dv") == 0) {    // Assumed to be a DV Video file    // First, make sure that the RTPSinks' buffers will be large enough to handle the huge size of DV frames (as big as 288000).    OutPacketBuffer::maxSize = 300000;    NEW_SMS("DV Video");    sms->addSubsession(DVVideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));  } else if (strcmp(extension, ".mkv") == 0 || strcmp(extension, ".webm") == 0) {    // Assumed to be a Matroska file (note that WebM ('.webm') files are also Matroska files)    OutPacketBuffer::maxSize = 100000; // allow for some possibly large VP8 or VP9 frames    NEW_SMS("Matroska video+audio+(optional)subtitles");    // Create a Matroska file server demultiplexor for the specified file.    // (We enter the event loop to wait for this to complete.)    MatroskaDemuxCreationState creationState;    creationState.watchVariable = 0;    MatroskaFileServerDemux::createNew(env, fileName, onMatroskaDemuxCreation, &creationState);    env.taskScheduler().doEventLoop(&creationState.watchVariable);    ServerMediaSubsession* smss;    while ((smss = creationState.demux->newServerMediaSubsession()) != NULL) {      sms->addSubsession(smss);    }  } else if (strcmp(extension, ".ogg") == 0 || strcmp(extension, ".ogv") == 0 || strcmp(extension, ".opus") == 0) {    // Assumed to be an Ogg file    NEW_SMS("Ogg video and/or audio");    // Create a Ogg file server demultiplexor for the specified file.    // (We enter the event loop to wait for this to complete.)    OggDemuxCreationState creationState;    creationState.watchVariable = 0;    OggFileServerDemux::createNew(env, fileName, onOggDemuxCreation, &creationState);    env.taskScheduler().doEventLoop(&creationState.watchVariable);    ServerMediaSubsession* smss;    while ((smss = creationState.demux->newServerMediaSubsession()) != NULL) {      sms->addSubsession(smss);    }  }  return sms;}

2、添加LiveADTSAudioServerMediaSubsession

#ifndef _H264_STREAM_FILE_SOURCE_HH#define _H264_STREAM_FILE_SOURCE_HH#ifndef _FRAMED_FILE_SOURCE_HH#include "FramedFileSource.hh"#endif#include<pthread.h>#include "semaphore.h"#define H264_BUF_SIZE 150000#define H264_BUF_COUNT 10typedef void (*CB_FUN)(void);extern void h264_buf_init();extern void h264_buf_destroy();extern Boolean h264_buf_full();extern Boolean h264_buf_empty();extern int h264_buf_put(unsigned char* buf,int len);extern unsigned char* h264_buf_get(int* len);extern sem_t h264_f;extern sem_t h264_e;extern int b264IsInit;extern CB_FUN startfun;extern CB_FUN endfun;class LiveH264StreamSource: public FramedSource {public:  static LiveH264StreamSource* createNew(UsageEnvironment& env, char const* fileName, unsigned preferredFrameSize = 0, unsigned playTimePerFrame = 0);  // "preferredFrameSize" == 0 means 'no preference'  // "playTimePerFrame" is in microseconds/*  static LiveH264StreamSource* createNew(UsageEnvironment& env, unsigned preferredFrameSize = 0, unsigned playTimePerFrame = 0);      // an alternative version of "createNew()" that's used if you already have      // an open file.*/  u_int64_t fileSize() const { return fFileSize; }      // 0 means zero-length, unbounded, or unknown  void seekToByteAbsolute(u_int64_t byteNumber, u_int64_t numBytesToStream = 0);    // if "numBytesToStream" is >0, then we limit the stream to that number of bytes, before treating it as EOF  void seekToByteRelative(int64_t offset, u_int64_t numBytesToStream = 0);  void seekToEnd(); // to force EOF handling on the next readprotected:  LiveH264StreamSource(UsageEnvironment& env,       unsigned preferredFrameSize,       unsigned playTimePerFrame);// called only by createNew()  virtual ~LiveH264StreamSource();  static void fileReadableHandler(LiveH264StreamSource* source, int mask);  void doReadFromFile();private:  // redefined virtual functions:  virtual void doGetNextFrame();  virtual void doStopGettingFrames();protected:  u_int64_t fFileSize;private:  unsigned fPreferredFrameSize;  unsigned fPlayTimePerFrame;  Boolean fFidIsSeekable;  unsigned fLastPlayTime;  Boolean fHaveStartedReading;  Boolean fLimitNumBytesToStream;  u_int64_t fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True};#endif


#include "LiveADTSAudioServerMediaSubsession.hh"#include "LiveADTSAudioSource.hh"#include "MPEG4GenericRTPSink.hh"LiveADTSAudioServerMediaSubsession*LiveADTSAudioServerMediaSubsession::createNew(UsageEnvironment& env,     char const* fileName,     Boolean reuseFirstSource) {  return new LiveADTSAudioServerMediaSubsession(env, fileName, reuseFirstSource);}LiveADTSAudioServerMediaSubsession::LiveADTSAudioServerMediaSubsession(UsageEnvironment& env,    char const* fileName, Boolean reuseFirstSource)  : FileServerMediaSubsession(env, fileName, reuseFirstSource) {}LiveADTSAudioServerMediaSubsession::~LiveADTSAudioServerMediaSubsession() {}FramedSource* LiveADTSAudioServerMediaSubsession::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {  estBitrate = 96; // kbps, estimate  return LiveADTSAudioSource::createNew(envir());}RTPSink* LiveADTSAudioServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,   unsigned char rtpPayloadTypeIfDynamic,   FramedSource* inputSource) {  LiveADTSAudioSource* adtsSource = (LiveADTSAudioSource*)inputSource;  return MPEG4GenericRTPSink::createNew(envir(), rtpGroupsock,rtpPayloadTypeIfDynamic,adtsSource->samplingFrequency(),"audio", "AAC-hbr", adtsSource->configStr(),adtsSource->numChannels());}

3、添加LiveADTSAudioSource类

#ifndef _LiveADTSAudioSource_HH#define _LiveADTSAudioSource_HH#ifndef _FRAMED_FILE_SOURCE_HH#include "FramedFileSource.hh"#endif#include<pthread.h>#include "semaphore.h"#define AAC_BUF_SIZE 10000#define AAC_BUF_COUNT 20extern void aac_buf_init();extern Boolean aac_buf_full();extern Boolean aac_buf_empty();extern int aac_buf_put(unsigned char* buf,int len);extern unsigned char* aac_buf_get();extern void aac_buf_destroy();extern sem_t aac_f;extern sem_t aac_e;extern int bIsInit;class LiveADTSAudioSource: public FramedSource {public:  static LiveADTSAudioSource* createNew(UsageEnvironment& env);  unsigned samplingFrequency() const { return fSamplingFrequency; }  unsigned numChannels() const { return fNumChannels; }  char const* configStr() const { return fConfigStr; }      // returns the 'AudioSpecificConfig' for this stream (in ASCII form)private:  LiveADTSAudioSource(UsageEnvironment& env, u_int8_t profile,      u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration);// called only by createNew()  virtual ~LiveADTSAudioSource();private:  // redefined virtual functions:  virtual void doGetNextFrame();private:  unsigned fSamplingFrequency;  unsigned fNumChannels;  unsigned fuSecsPerFrame;  char fConfigStr[5];};#endif

#include "LiveADTSAudioSource.hh"#include "InputFile.hh"#include <GroupsockHelper.hh>////////// ADTSAudioFileSource //////////static unsigned const samplingFrequencyTable[16] = {  96000, 88200, 64000, 48000,  44100, 32000, 24000, 22050,  16000, 12000, 11025, 8000,  7350, 0, 0, 0};unsigned char aac_framebuf[AAC_BUF_COUNT][AAC_BUF_SIZE];int aac_frame_len[AAC_BUF_COUNT];int aac_buf_head;int aac_buf_tail;int aac_buf_size;void aac_buf_init();void aac_buf_destroy();Boolean aac_buf_full();Boolean aac_buf_empty();int aac_buf_put(unsigned char* buf,int len);unsigned char* aac_buf_get();sem_t aac_f;sem_t aac_e;sem_t aac_m;int bIsInit = 0;void aac_buf_init(){if(bIsInit == 0){    sem_init(&aac_f,0,0);    sem_init(&aac_e,0,AAC_BUF_COUNT);    sem_init(&aac_m,0,1);aac_buf_head = 0;aac_buf_tail = 0;aac_buf_size = 0;}}Boolean aac_buf_full(){if(aac_buf_size == AAC_BUF_COUNT)return True;return False;}Boolean aac_buf_empty(){if(aac_buf_size == 0)return True;return False;}int aac_buf_put(unsigned char* buf,int len){sem_wait(&aac_e);sem_wait(&aac_m);bzero(aac_framebuf[aac_buf_tail],AAC_BUF_SIZE);memcpy(aac_framebuf[aac_buf_tail],buf,len);aac_frame_len[aac_buf_tail] = len;aac_buf_tail = (aac_buf_tail + 1)%AAC_BUF_COUNT;aac_buf_size++;sem_post(&aac_m);sem_post(&aac_f);}unsigned char* aac_buf_get(){sem_wait(&aac_m);unsigned char* rt = aac_framebuf[aac_buf_head];aac_buf_head = (aac_buf_head+1)%AAC_BUF_COUNT;aac_buf_size--;sem_post(&aac_m);return rt;}void aac_buf_destroy(){sem_destroy(&aac_f);sem_destroy(&aac_e);sem_destroy(&aac_m);}LiveADTSAudioSource*LiveADTSAudioSource::createNew(UsageEnvironment& env) {        aac_buf_init();    bIsInit = 1;    return new LiveADTSAudioSource(env, 1, 4, 2);}LiveADTSAudioSource::LiveADTSAudioSource(UsageEnvironment& env, u_int8_t profile,      u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration)  : FramedSource(env) {   fSamplingFrequency = samplingFrequencyTable[samplingFrequencyIndex];  fNumChannels = channelConfiguration == 0 ? 2 : channelConfiguration;  fuSecsPerFrame    = (1024/*samples-per-frame*/*1000000) / fSamplingFrequency/*samples-per-second*/;  // Construct the 'AudioSpecificConfig', and from it, the corresponding ASCII string:  unsigned char audioSpecificConfig[2];  u_int8_t const audioObjectType = profile + 1;  audioSpecificConfig[0] = (audioObjectType<<3) | (samplingFrequencyIndex>>1);  audioSpecificConfig[1] = (samplingFrequencyIndex<<7) | (channelConfiguration<<3);  sprintf(fConfigStr, "%02X%02x", audioSpecificConfig[0], audioSpecificConfig[1]);  //env << "liveADTSAudioSource : construct\n";}LiveADTSAudioSource::~LiveADTSAudioSource() {}// Note: We should change the following to use asynchronous file reading, #####// as we now do with ByteStreamFileSource. #####void LiveADTSAudioSource::doGetNextFrame() {  // Begin by reading the 7-byte fixed_variable headers:  sem_wait(&aac_f);  unsigned char* cur = aac_buf_get();  int pos = 0;  unsigned char* headers;  headers = cur;  // Extract important fields from the headers:  Boolean protection_absent = headers[1]&0x01;  u_int16_t frame_length    = ((headers[3]&0x03)<<11) | (headers[4]<<3) | ((headers[5]&0xE0)>>5);if(0){  u_int16_t syncword = (headers[0]<<4) | (headers[1]>>4);  fprintf(stderr, "Read frame: syncword 0x%x, protection_absent %d, frame_length %d\n", syncword, protection_absent, frame_length);  if (syncword != 0xFFF) fprintf(stderr, "WARNING: Bad syncword!\n");}  unsigned numBytesToRead    = frame_length > 7 ? frame_length - 7 : 0;  pos = 7;  // If there's a 'crc_check' field, skip it:  if (!protection_absent) {    pos += 2;    numBytesToRead = numBytesToRead > 2 ? numBytesToRead - 2 : 0;  }  // Next, read the raw frame data into the buffer provided:  if (numBytesToRead > fMaxSize) {    fNumTruncatedBytes = numBytesToRead - fMaxSize;    numBytesToRead = fMaxSize;  }  memcpy(fTo,cur + pos,numBytesToRead);  sem_post(&aac_e);  int numBytesRead = numBytesToRead;  fFrameSize = numBytesRead;  fNumTruncatedBytes += numBytesToRead - numBytesRead;  // Set the 'presentation time':  if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {    // This is the first frame, so use the current time:    gettimeofday(&fPresentationTime, NULL);  } else {    // Increment by the play time of the previous frame:    unsigned uSeconds = fPresentationTime.tv_usec + fuSecsPerFrame;    fPresentationTime.tv_sec += uSeconds/1000000;    fPresentationTime.tv_usec = uSeconds%1000000;  }  fDurationInMicroseconds = fuSecsPerFrame;  // Switch to another task, and inform the reader that he has data:  nextTask() = envir().taskScheduler().scheduleDelayedTask(0,(TaskFunc*)FramedSource::afterGetting, this);}

4、添加LiveVideoFileServerMediaSubsession类

#ifndef _LIVE_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH#define _LIVE_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH#include "FileServerMediaSubsession.hh"#endifclass LiveVideoFileServerMediaSubsession: public FileServerMediaSubsession {public:  static LiveVideoFileServerMediaSubsession*  createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource);  // Used to implement "getAuxSDPLine()":  void checkForAuxSDPLine1();  void afterPlayingDummy1();protected:  LiveVideoFileServerMediaSubsession(UsageEnvironment& env,      char const* fileName, Boolean reuseFirstSource);      // called only by createNew();  virtual ~LiveVideoFileServerMediaSubsession();  void setDoneFlag() { fDoneFlag = ~0; }protected: // redefined virtual functions  virtual char const* getAuxSDPLine(RTPSink* rtpSink,    FramedSource* inputSource);  virtual FramedSource* createNewStreamSource(unsigned clientSessionId,      unsigned& estBitrate);  virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,                                    unsigned char rtpPayloadTypeIfDynamic,    FramedSource* inputSource);private:  char* fAuxSDPLine;  char fDoneFlag; // used when setting up "fAuxSDPLine"  RTPSink* fDummyRTPSink; // ditto};#endif

#include "LiveVideoFileServerMediaSubsession.hh"#include "H264VideoRTPSink.hh"#include "LiveH264StreamSource.hh"#include "H264VideoStreamFramer.hh"LiveVideoFileServerMediaSubsession*LiveVideoFileServerMediaSubsession::createNew(UsageEnvironment& env,      char const* fileName,      Boolean reuseFirstSource) {  return new LiveVideoFileServerMediaSubsession(env, fileName, reuseFirstSource);}LiveVideoFileServerMediaSubsession::LiveVideoFileServerMediaSubsession(UsageEnvironment& env,       char const* fileName, Boolean reuseFirstSource)  : FileServerMediaSubsession(env, fileName, reuseFirstSource),    fAuxSDPLine(NULL), fDoneFlag(0), fDummyRTPSink(NULL) {}LiveVideoFileServerMediaSubsession::~LiveVideoFileServerMediaSubsession() {  delete[] fAuxSDPLine;}static void afterPlayingDummy(void* clientData) {  LiveVideoFileServerMediaSubsession* subsess = (LiveVideoFileServerMediaSubsession*)clientData;  subsess->afterPlayingDummy1();}void LiveVideoFileServerMediaSubsession::afterPlayingDummy1() {  // Unschedule any pending 'checking' task:  envir().taskScheduler().unscheduleDelayedTask(nextTask());  // Signal the event loop that we're done:  setDoneFlag();}static void checkForAuxSDPLine(void* clientData) {  LiveVideoFileServerMediaSubsession* subsess = (LiveVideoFileServerMediaSubsession*)clientData;  subsess->checkForAuxSDPLine1();}void LiveVideoFileServerMediaSubsession::checkForAuxSDPLine1() {  char const* dasl;  if (fAuxSDPLine != NULL) {    // Signal the event loop that we're done:    setDoneFlag();  } else if (fDummyRTPSink != NULL && (dasl = fDummyRTPSink->auxSDPLine()) != NULL) {    fAuxSDPLine = strDup(dasl);    fDummyRTPSink = NULL;    // Signal the event loop that we're done:    setDoneFlag();  } else if (!fDoneFlag) {    // try again after a brief delay:    int uSecsToDelay = 100000; // 100 ms    nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay,      (TaskFunc*)checkForAuxSDPLine, this);  }}char const* LiveVideoFileServerMediaSubsession::getAuxSDPLine(RTPSink* rtpSink, FramedSource* inputSource) {  if (fAuxSDPLine != NULL) return fAuxSDPLine; // it's already been set up (for a previous client)  if (fDummyRTPSink == NULL) { // we're not already setting it up for another, concurrent stream    // Note: For H264 video files, the 'config' information ("profile-level-id" and "sprop-parameter-sets") isn't known    // until we start reading the file.  This means that "rtpSink"s "auxSDPLine()" will be NULL initially,    // and we need to start reading data from our file until this changes.    fDummyRTPSink = rtpSink;    // Start reading the file:    fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this);    // Check whether the sink's 'auxSDPLine()' is ready:    checkForAuxSDPLine(this);  }  envir().taskScheduler().doEventLoop(&fDoneFlag);  return fAuxSDPLine;}FramedSource* LiveVideoFileServerMediaSubsession::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {  estBitrate = 500; // kbps, estimate  // Create the video source:  LiveH264StreamSource* fileSource = LiveH264StreamSource::createNew(envir(), fFileName);  if (fileSource == NULL) return NULL;  fFileSize = fileSource->fileSize();  // Create a framer for the Video Elementary Stream:  return H264VideoStreamFramer::createNew(envir(), fileSource);}RTPSink* LiveVideoFileServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,   unsigned char rtpPayloadTypeIfDynamic,   FramedSource* /*inputSource*/) {  return H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic);}

5、添加LiveH264StreamSource类

#ifndef _H264_STREAM_FILE_SOURCE_HH#define _H264_STREAM_FILE_SOURCE_HH#ifndef _FRAMED_FILE_SOURCE_HH#include "FramedFileSource.hh"#endif#include<pthread.h>#include "semaphore.h"#define H264_BUF_SIZE 150000#define H264_BUF_COUNT 10typedef void (*CB_FUN)(void);extern void h264_buf_init();extern void h264_buf_destroy();extern Boolean h264_buf_full();extern Boolean h264_buf_empty();extern int h264_buf_put(unsigned char* buf,int len);extern unsigned char* h264_buf_get(int* len);extern sem_t h264_f;extern sem_t h264_e;extern int b264IsInit;extern CB_FUN startfun;extern CB_FUN endfun;class LiveH264StreamSource: public FramedSource {public:  static LiveH264StreamSource* createNew(UsageEnvironment& env, char const* fileName, unsigned preferredFrameSize = 0, unsigned playTimePerFrame = 0);  // "preferredFrameSize" == 0 means 'no preference'  // "playTimePerFrame" is in microseconds/*  static LiveH264StreamSource* createNew(UsageEnvironment& env, unsigned preferredFrameSize = 0, unsigned playTimePerFrame = 0);      // an alternative version of "createNew()" that's used if you already have      // an open file.*/  u_int64_t fileSize() const { return fFileSize; }      // 0 means zero-length, unbounded, or unknown  void seekToByteAbsolute(u_int64_t byteNumber, u_int64_t numBytesToStream = 0);    // if "numBytesToStream" is >0, then we limit the stream to that number of bytes, before treating it as EOF  void seekToByteRelative(int64_t offset, u_int64_t numBytesToStream = 0);  void seekToEnd(); // to force EOF handling on the next readprotected:  LiveH264StreamSource(UsageEnvironment& env,       unsigned preferredFrameSize,       unsigned playTimePerFrame);// called only by createNew()  virtual ~LiveH264StreamSource();  static void fileReadableHandler(LiveH264StreamSource* source, int mask);  void doReadFromFile();private:  // redefined virtual functions:  virtual void doGetNextFrame();  virtual void doStopGettingFrames();protected:  u_int64_t fFileSize;private:  unsigned fPreferredFrameSize;  unsigned fPlayTimePerFrame;  Boolean fFidIsSeekable;  unsigned fLastPlayTime;  Boolean fHaveStartedReading;  Boolean fLimitNumBytesToStream;  u_int64_t fNumBytesToStream; // used iff "fLimitNumBytesToStream" is True};#endif

#include "LiveH264StreamSource.hh"#include "InputFile.hh"#include "GroupsockHelper.hh"////////// LiveH264StreamSource //////////unsigned char h264_framebuf[H264_BUF_COUNT][H264_BUF_SIZE];int h264_frame_len[H264_BUF_COUNT];int h264_buf_head;int h264_buf_tail;int h264_buf_size;void h264_buf_init();void h264_buf_destroy();Boolean h264_buf_full();Boolean h264_buf_empty();int h264_buf_put(unsigned char* buf,int len);unsigned char* h264_buf_get();sem_t h264_f;sem_t h264_e;sem_t h264_m;int b264IsInit = 0;CB_FUN startfun = NULL;CB_FUN endfun = NULL;unsigned char obuf[H264_BUF_SIZE];unsigned olen = 0;void h264_buf_init(){if(b264IsInit == 0){    sem_init(&h264_f,1,0);    sem_init(&h264_e,1,H264_BUF_COUNT);    sem_init(&h264_m,1,1);h264_buf_head = 0;h264_buf_tail = 0;h264_buf_size = 0;//printf("must 1\n");}}Boolean h264_buf_full(){if(h264_buf_size == H264_BUF_COUNT)return True;return False;}Boolean h264_buf_empty(){if(h264_buf_size == 0)return True;return False;}int h264_buf_put(unsigned char* buf,int len){sem_wait(&h264_e);sem_wait(&h264_m);bzero(h264_framebuf[h264_buf_tail],H264_BUF_SIZE);memcpy(h264_framebuf[h264_buf_tail],buf,len);h264_frame_len[h264_buf_tail] = len;h264_buf_tail = (h264_buf_tail + 1)%H264_BUF_COUNT;h264_buf_size++;sem_post(&h264_f);sem_post(&h264_m);}unsigned char* h264_buf_get(int* len){sem_wait(&h264_m);unsigned char* rt = h264_framebuf[h264_buf_head];*len = h264_frame_len[h264_buf_head];h264_buf_head = (h264_buf_head+1)%H264_BUF_COUNT;h264_buf_size--;sem_post(&h264_m);return rt;}void h264_buf_destroy(){sem_destroy(&h264_f);sem_destroy(&h264_e);sem_destroy(&h264_m);}LiveH264StreamSource*LiveH264StreamSource::createNew(UsageEnvironment& env, char const* fileName,unsigned preferredFrameSize,unsigned playTimePerFrame) {    h264_buf_init();    b264IsInit = 1;  LiveH264StreamSource* newSource    = new LiveH264StreamSource(env, preferredFrameSize, playTimePerFrame);if(startfun != NULL){startfun();}     return newSource;}/*LiveH264StreamSource*LiveH264StreamSource::createNew(UsageEnvironment& env, unsigned preferredFrameSize,unsigned playTimePerFrame) {  LiveH264StreamSource* newSource = new LiveH264StreamSource(env, preferredFrameSize, playTimePerFrame);  return newSource;}*/void LiveH264StreamSource::seekToByteAbsolute(u_int64_t byteNumber, u_int64_t numBytesToStream) {  fNumBytesToStream = numBytesToStream;  fLimitNumBytesToStream = fNumBytesToStream > 0;}void LiveH264StreamSource::seekToByteRelative(int64_t offset, u_int64_t numBytesToStream) {  fNumBytesToStream = numBytesToStream;  fLimitNumBytesToStream = fNumBytesToStream > 0;}void LiveH264StreamSource::seekToEnd() {}LiveH264StreamSource::LiveH264StreamSource(UsageEnvironment& env,    unsigned preferredFrameSize,   unsigned playTimePerFrame)  : FramedSource(env), fFileSize(0), fPreferredFrameSize(preferredFrameSize),    fPlayTimePerFrame(playTimePerFrame), fLastPlayTime(0),    fHaveStartedReading(False), fLimitNumBytesToStream(False), fNumBytesToStream(0) {  // Test whether the file is seekable  fFidIsSeekable = False;}LiveH264StreamSource::~LiveH264StreamSource() {   if(endfun != NULL)   {endfun();   }}void LiveH264StreamSource::doGetNextFrame() {  doReadFromFile();}void LiveH264StreamSource::doStopGettingFrames() {  //envir().taskScheduler().unscheduleDelayedTask(nextTask());}void LiveH264StreamSource::fileReadableHandler(LiveH264StreamSource* source, int /*mask*/) {  if (!source->isCurrentlyAwaitingData()) {    source->doStopGettingFrames(); // we're not ready for the data yet    return;  }  source->doReadFromFile();}void LiveH264StreamSource::doReadFromFile() {  // Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less)  if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) {    fMaxSize = (unsigned)fNumBytesToStream;  }  if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) {    fMaxSize = fPreferredFrameSize;  }  sem_wait(&h264_f);  int len = 0;  unsigned char* frame = h264_buf_get(&len);    if(olen > 0)  {  memcpy(fTo,obuf,olen);  }    if(len + olen>= fMaxSize)  {  unsigned need = fMaxSize-olen;  memcpy(&fTo[olen],frame,need);fFrameSize = fMaxSize;olen = len - need;memcpy(obuf,&frame[need],olen);    }else{  memcpy(&fTo[olen],frame,len+ olen);fFrameSize = olen + len;olen = 0;  }    sem_post(&h264_e);   //fFrameSize = fread(fTo, 1, fMaxSize, fFid);  //fwrite(fTo,fFrameSize,1,file);      if (fFrameSize == 0) {    //handleClosure();    //return;  }  fNumBytesToStream -= fFrameSize;  // Set the 'presentation time':  if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) {    if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {      // This is the first frame, so use the current time:      gettimeofday(&fPresentationTime, NULL);    } else {      // Increment by the play time of the previous data:      unsigned uSeconds= fPresentationTime.tv_usec + fLastPlayTime;      fPresentationTime.tv_sec += uSeconds/1000000;      fPresentationTime.tv_usec = uSeconds%1000000;    }    // Remember the play time of this data:    fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize;    fDurationInMicroseconds = fLastPlayTime;  } else {    // We don't know a specific play time duration for this data,    // so just record the current time as being the 'presentation time':    gettimeofday(&fPresentationTime, NULL);  }  // To avoid possible infinite recursion, we need to return to the event loop to do this:  nextTask() = envir().taskScheduler().scheduleDelayedTask(0,(TaskFunc*)FramedSource::afterGetting, this);}

6、修改livemedia.hh,添加

<span style="color:#666666;">#include "LiveADTSAudioSource.hh"#include "LiveADTSAudioServerMediaSubsession.hh"#include "LiveVideoFileServerMediaSubsession.hh"#include "LiveH264StreamSource.hh"</span>

7、添加接口代码

#include <BasicUsageEnvironment.hh>#include "DynamicRTSPServer.hh"#include <liveMedia.hh>#include "version.hh"typedef void (*CB_FUN)(void);int Rtsp_Server_Start();int Rtsp_Server_Stop();int Rtsp_AAC_Frame(unsigned char* frame,int framelen);int Rtsp_H264_Frame(unsigned char* frame,int framelen);int Rtsp_Regist_Start_Routine(CB_FUN fun);int Rtsp_Regist_Stop_Routine(CB_FUN fun);int Rtsp_Port();

#include "librtspserv.hh"#include <pthread.h>pthread_t id;void* server_start(void* arg) {  // Begin by setting up our usage environment:  TaskScheduler* scheduler = BasicTaskScheduler::createNew();  UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);  UserAuthenticationDatabase* authDB = NULL;#ifdef ACCESS_CONTROL  // To implement client access control to the RTSP server, do the following:  authDB = new UserAuthenticationDatabase;  authDB->addUserRecord("username1", "password1"); // replace these with real strings  // Repeat the above with each <username>, <password> that you wish to allow  // access to the server.#endif  // Create the RTSP server.  Try first with the default port number (554),  // and then with the alternative port number (8554):  RTSPServer* rtspServer;  portNumBits rtspServerPortNum = 554;  rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);  if (rtspServer == NULL) {    rtspServerPortNum = 8554;    rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);  }  if (rtspServer == NULL) {    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";    exit(1);  }  *env << "LIVE555 Media Server\n";  *env << "\tversion " << MEDIA_SERVER_VERSION_STRING       << " (LIVE555 Streaming Media library version "       << LIVEMEDIA_LIBRARY_VERSION_STRING << ").\n";  char* urlPrefix = rtspServer->rtspURLPrefix();  *env << "Play streams from this server using the URL\n\t"       << urlPrefix << "<filename>\nwhere <filename> is a file present in the current directory.\n";  *env << "Each file's type is inferred from its name suffix:\n";  *env << "\t\".264\" => a H.264 Video Elementary Stream file\n";  *env << "\t\".265\" => a H.265 Video Elementary Stream file\n";  *env << "\t\".aac\" => an AAC Audio (ADTS format) file\n";  *env << "\t\".ac3\" => an AC-3 Audio file\n";  *env << "\t\".amr\" => an AMR Audio file\n";  *env << "\t\".dv\" => a DV Video file\n";  *env << "\t\".m4e\" => a MPEG-4 Video Elementary Stream file\n";  *env << "\t\".mkv\" => a Matroska audio+video+(optional)subtitles file\n";  *env << "\t\".mp3\" => a MPEG-1 or 2 Audio file\n";  *env << "\t\".mpg\" => a MPEG-1 or 2 Program Stream (audio+video) file\n";  *env << "\t\".ogg\" or \".ogv\" or \".opus\" => an Ogg audio and/or video file\n";  *env << "\t\".ts\" => a MPEG Transport Stream file\n";  *env << "\t\t(a \".tsx\" index file - if present - provides server 'trick play' support)\n";  *env << "\t\".vob\" => a VOB (MPEG-2 video with AC-3 audio) file\n";  *env << "\t\".wav\" => a WAV Audio file\n";  *env << "\t\".webm\" => a WebM audio(Vorbis)+video(VP8) file\n";  *env << "See http://www.live555.com/mediaServer/ for additional documentation.\n";  // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.  // Try first with the default HTTP port (80), and then with the alternative HTTP  // port numbers (8000 and 8080).  if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {    *env << "(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling, or for HTTP live streaming (for indexed Transport Stream files only).)\n";  } else {    *env << "(RTSP-over-HTTP tunneling is not available.)\n";  }  env->taskScheduler().doEventLoop(); // does not return  return 0; // only to prevent compiler warning}int Rtsp_Server_Start(){pthread_create(&id,NULL,server_start,NULL);}int Rtsp_AAC_Frame(unsigned char* frame,int framelen){while(bIsInit == 0){usleep(1000*100);}aac_buf_put(frame,framelen);usleep(0);return 0;}int Rtsp_Server_Stop(){//printf("destory.....\n");h264_buf_destroy();aac_buf_destroy();}int Rtsp_H264_Frame(unsigned char* frame,int framelen){while(b264IsInit == 0){usleep(1000*100);//printf("usleep(1000*80);\n");}int i = 0;//printf("framelen = %d,count = %d,mod = %d\n",framelen,framelen/H264_BUF_SIZE,framelen%H264_BUF_SIZE);for(i = 0; i < framelen/H264_BUF_SIZE;i++){h264_buf_put(&frame[i*H264_BUF_SIZE],H264_BUF_SIZE);}int lastsize = framelen % H264_BUF_SIZE;if(lastsize > 0){h264_buf_put(&frame[i*H264_BUF_SIZE],lastsize);}usleep(0);return 0;}int Rtsp_Regist_Start_Routine(CB_FUN fun){startfun = fun;return 0;}int Rtsp_Regist_Stop_Routine(CB_FUN fun){endfun = fun;return 0;}int Rtsp_Port(){}


0 0
原创粉丝点击