⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpeg2transportfileservermediasubsession.cpp

📁 c++实现的流媒体库,和mplayer结合就可以实现多媒体的网络播放,属于开源项目,很值得研究.
💻 CPP
字号:
/**********This library is free software; you can redistribute it and/or modify it underthe terms of the GNU Lesser General Public License as published by theFree Software Foundation; either version 2.1 of the License, or (at youroption) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)This library is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License formore details.You should have received a copy of the GNU Lesser General Public Licensealong with this library; if not, write to the Free Software Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA  02111-1307  USA**********/// "liveMedia"// Copyright (c) 1996-2007 Live Networks, Inc.  All rights reserved.// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s// on demand, from a MPEG-2 Transport Stream file.// Implementation#include "MPEG2TransportFileServerMediaSubsession.hh"#include "SimpleRTPSink.hh"#include "ByteStreamFileSource.hh"#include "MPEG2TransportStreamTrickModeFilter.hh"#include "MPEG2TransportStreamFromESSource.hh"#include "MPEG2TransportStreamFramer.hh"// We assume that the video - in the original Transport Stream file - is MPEG-2.// If, instead, it is MPEG-1, then change the following definition to 1:#define VIDEO_MPEG_VERSION 2////////// ClientTrickPlayState definition //////////// This class encapsulates the 'trick play' state for each current client (for// a given "MPEG2TransportFileServerMediaSubsession" - i.e., Transport Stream file).class ClientTrickPlayState {public:  ClientTrickPlayState(MPEG2TransportStreamIndexFile* indexFile);  // Functions to bring "fNPT", "fTSRecordNum" and "fIxRecordNum" in sync:  void updateStateFromNPT(float npt);  void updateStateOnScaleChange();  void updateStateOnPlayChange(Boolean reverseToPreviousVSH);  void handleStreamDeletion();  void setSource(MPEG2TransportStreamFramer* framer);  void setNextScale(float nextScale) { fNextScale = nextScale; }  Boolean areChangingScale() const { return fNextScale != fScale; }private:  void updateTSRecordNum();  void reseekOriginalTransportStreamSource();private:  MPEG2TransportStreamIndexFile* fIndexFile;  ByteStreamFileSource* fOriginalTransportStreamSource;  MPEG2TransportStreamTrickModeFilter* fTrickModeFilter;  MPEG2TransportStreamFromESSource* fTrickPlaySource;  MPEG2TransportStreamFramer* fFramer;  float fScale, fNextScale, fNPT;  unsigned long fTSRecordNum, fIxRecordNum;};////////// MPEG2TransportFileServerMediaSubsession implementation //////////MPEG2TransportFileServerMediaSubsession*MPEG2TransportFileServerMediaSubsession::createNew(UsageEnvironment& env,						   char const* fileName,						   char const* indexFileName,						   Boolean reuseFirstSource) {  if (indexFileName != NULL && reuseFirstSource) {    // It makes no sense to support trick play if all clients use the same source.  Fix this:    env << "MPEG2TransportFileServerMediaSubsession::createNew(): ignoring the index file name, because \"reuseFirstSource\" is set\n";    indexFileName = NULL;  }  MPEG2TransportStreamIndexFile* indexFile = MPEG2TransportStreamIndexFile::createNew(env, indexFileName);  return new MPEG2TransportFileServerMediaSubsession(env, fileName, indexFile,						     reuseFirstSource);}MPEG2TransportFileServerMediaSubsession::MPEG2TransportFileServerMediaSubsession(UsageEnvironment& env,					  char const* fileName,					  MPEG2TransportStreamIndexFile* indexFile,					  Boolean reuseFirstSource)  : FileServerMediaSubsession(env, fileName, reuseFirstSource),    fIndexFile(indexFile), fDuration(0.0), fClientSessionHashTable(NULL) {  if (fIndexFile != NULL) { // we support 'trick play'    fDuration = fIndexFile->getPlayingDuration();    fClientSessionHashTable = HashTable::create(ONE_WORD_HASH_KEYS);  }}MPEG2TransportFileServerMediaSubsession::~MPEG2TransportFileServerMediaSubsession() {  if (fIndexFile != NULL) { // we support 'trick play'    Medium::close(fIndexFile);    // Clean out the client session hash table:    while (1) {      ClientTrickPlayState* client	= (ClientTrickPlayState*)(fClientSessionHashTable->RemoveNext());      if (client == NULL) break;      delete client;    }    delete fClientSessionHashTable;  }}#define TRANSPORT_PACKET_SIZE 188#define TRANSPORT_PACKETS_PER_NETWORK_PACKET 7// The product of these two numbers must be enough to fit within a network packetvoid MPEG2TransportFileServerMediaSubsession::startStream(unsigned clientSessionId, void* streamToken, TaskFunc* rtcpRRHandler,	      void* rtcpRRHandlerClientData, unsigned short& rtpSeqNum,	      unsigned& rtpTimestamp) {  if (fIndexFile != NULL) { // we support 'trick play'    ClientTrickPlayState* client = lookupClient(clientSessionId);    if (client != NULL && client->areChangingScale()) {      // First, handle this like a "PAUSE", except that we back up to the previous VSH      client->updateStateOnPlayChange(True);      OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);      // Then, adjust for the change of scale:      client->updateStateOnScaleChange();    }  }  // Call the original, default version of this routine:  OnDemandServerMediaSubsession::startStream(clientSessionId, streamToken,					     rtcpRRHandler, rtcpRRHandlerClientData,					     rtpSeqNum, rtpTimestamp);}void MPEG2TransportFileServerMediaSubsession::pauseStream(unsigned clientSessionId, void* streamToken) {  if (fIndexFile != NULL) { // we support 'trick play'    ClientTrickPlayState* client = lookupClient(clientSessionId);    if (client != NULL) {      client->updateStateOnPlayChange(False);    }  }  // Call the original, default version of this routine:  OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);}void MPEG2TransportFileServerMediaSubsession::seekStream(unsigned clientSessionId, void* streamToken, float seekNPT) {  if (fIndexFile != NULL) { // we support 'trick play'    ClientTrickPlayState* client = lookupClient(clientSessionId);    if (client != NULL) {      client->updateStateFromNPT(seekNPT);    }  }  // Call the original, default version of this routine:  OnDemandServerMediaSubsession::seekStream(clientSessionId, streamToken, seekNPT);}void MPEG2TransportFileServerMediaSubsession::setStreamScale(unsigned clientSessionId, void* streamToken, float scale) {  if (fIndexFile != NULL) { // we support 'trick play'    ClientTrickPlayState* client = lookupClient(clientSessionId);    if (client != NULL) {      client->setNextScale(scale); // scale won't take effect until the next "PLAY"    }  }  // Call the original, default version of this routine:  OnDemandServerMediaSubsession::setStreamScale(clientSessionId, streamToken, scale);}void MPEG2TransportFileServerMediaSubsession::deleteStream(unsigned clientSessionId, void*& streamToken) {  if (fIndexFile != NULL) { // we support 'trick play'    ClientTrickPlayState* client = lookupClient(clientSessionId);    if (client != NULL) {      client->updateStateOnPlayChange(False);    }  }  // Call the original, default version of this routine:  OnDemandServerMediaSubsession::deleteStream(clientSessionId, streamToken);}FramedSource* MPEG2TransportFileServerMediaSubsession::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) {  estBitrate = 5000; // kbps, estimate  // Create the video source:  unsigned const inputDataChunkSize    = TRANSPORT_PACKETS_PER_NETWORK_PACKET*TRANSPORT_PACKET_SIZE;  ByteStreamFileSource* fileSource    = ByteStreamFileSource::createNew(envir(), fFileName, inputDataChunkSize);  if (fileSource == NULL) return NULL;  fFileSize = fileSource->fileSize();  // Create a framer for the Transport Stream:  MPEG2TransportStreamFramer* framer    = MPEG2TransportStreamFramer::createNew(envir(), fileSource);  if (fIndexFile != NULL) { // we support 'trick play'    // Keep state for this client (if we don't already have it):    ClientTrickPlayState* client = lookupClient(clientSessionId);    if (client == NULL) {      client = new ClientTrickPlayState(fIndexFile);      fClientSessionHashTable->Add((char const*)clientSessionId, client);    }    client->setSource(framer);  }  return framer;}RTPSink* MPEG2TransportFileServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock,		   unsigned char /*rtpPayloadTypeIfDynamic*/,		   FramedSource* /*inputSource*/) {  return SimpleRTPSink::createNew(envir(), rtpGroupsock,				  33, 90000, "video", "MP2T",				  1, True, False /*no 'M' bit*/);}void MPEG2TransportFileServerMediaSubsession::testScaleFactor(float& scale) {  if (fIndexFile != NULL && fDuration > 0.0) {    // We support any integral scale, other than 0    int iScale = scale < 0.0 ? (int)(scale - 0.5f) : (int)(scale + 0.5f); // round    if (iScale == 0) iScale = 1;    scale = (float)iScale;  } else {    scale = 1.0f;  }}float MPEG2TransportFileServerMediaSubsession::duration() const {  return fDuration;}ClientTrickPlayState* MPEG2TransportFileServerMediaSubsession::lookupClient(unsigned clientSessionId) {  return (ClientTrickPlayState*)(fClientSessionHashTable->Lookup((char const*)clientSessionId));}////////// ClientTrickPlayState implementation //////////ClientTrickPlayState::ClientTrickPlayState(MPEG2TransportStreamIndexFile* indexFile)  : fIndexFile(indexFile),    fOriginalTransportStreamSource(NULL),    fTrickModeFilter(NULL), fTrickPlaySource(NULL),    fFramer(NULL),    fScale(1.0f), fNextScale(1.0f), fNPT(0.0f),    fTSRecordNum(0), fIxRecordNum(0) {}void ClientTrickPlayState::updateStateFromNPT(float npt) {  fNPT = npt;  // Map "fNPT" to the corresponding Transport Stream and Index record numbers:  unsigned long tsRecordNum, ixRecordNum;  fIndexFile->lookupTSPacketNumFromNPT(fNPT, tsRecordNum, ixRecordNum);  updateTSRecordNum();  if (tsRecordNum != fTSRecordNum) {    fTSRecordNum = tsRecordNum;    fIxRecordNum = ixRecordNum;    // Seek the source to the new record number:    reseekOriginalTransportStreamSource();    // Note: We assume that we're asked to seek only in normal    // (i.e., non trick play) mode, so we don't seek within the trick    // play source (if any).    fFramer->clearPIDStatusTable();  }}void ClientTrickPlayState::updateStateOnScaleChange() {  fScale = fNextScale;  // Change our source objects to reflect the change in scale:  // First, close the existing trick play source (if any):  if (fTrickPlaySource != NULL) {    fTrickModeFilter->forgetInputSource();        // so that the underlying Transport Stream source doesn't get deleted by:    Medium::close(fTrickPlaySource);    fTrickPlaySource = NULL;    fTrickModeFilter = NULL;  }  if (fNextScale != 1.0f) {    // Create a new trick play filter from the original Transport Stream source:    UsageEnvironment& env = fIndexFile->envir(); // alias    fTrickModeFilter = MPEG2TransportStreamTrickModeFilter      ::createNew(env, fOriginalTransportStreamSource, fIndexFile, int(fNextScale));    fTrickModeFilter->seekTo(fTSRecordNum, fIxRecordNum);    // And generate a Transport Stream from this:    fTrickPlaySource = MPEG2TransportStreamFromESSource::createNew(env);    fTrickPlaySource->addNewVideoSource(fTrickModeFilter, VIDEO_MPEG_VERSION);    fFramer->changeInputSource(fTrickPlaySource);  } else {    // Switch back to the original Transport Stream source:    reseekOriginalTransportStreamSource();    fFramer->changeInputSource(fOriginalTransportStreamSource);  }}void ClientTrickPlayState::updateStateOnPlayChange(Boolean reverseToPreviousVSH) {  updateTSRecordNum();  if (fTrickPlaySource == NULL) {    // We were in regular (1x) play. Use the index file to look up the    // index record number and npt from the current transport number:    fIndexFile->lookupPCRFromTSPacketNum(fTSRecordNum, reverseToPreviousVSH, fNPT, fIxRecordNum);  } else {    // We were in trick mode, and so already have the index record number.    // Get the transport record number and npt from this:    fIxRecordNum = fTrickModeFilter->nextIndexRecordNum();    if ((long)fIxRecordNum < 0) fIxRecordNum = 0; // we were at the start of the file    unsigned long transportRecordNum;    float pcr;    u_int8_t offset, size, recordType; // all dummy    if (fIndexFile->readIndexRecordValues(fIxRecordNum, transportRecordNum,					  offset, size, pcr, recordType)) {      fTSRecordNum = transportRecordNum;      fNPT = pcr;    }  }}void ClientTrickPlayState::setSource(MPEG2TransportStreamFramer* framer) {  fFramer = framer;  fOriginalTransportStreamSource = (ByteStreamFileSource*)(framer->inputSource());}void ClientTrickPlayState::updateTSRecordNum(){  if (fFramer != NULL) fTSRecordNum += fFramer->tsPacketCount();}void ClientTrickPlayState::reseekOriginalTransportStreamSource() {  u_int64_t tsRecordNum64 = (u_int64_t)fTSRecordNum;  fOriginalTransportStreamSource->seekToByteAbsolute(tsRecordNum64*TRANSPORT_PACKET_SIZE);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -