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

📄 mpeg2transportstreamtrickmodefilter.cpp

📁 H.264 RTSP 串流(live 555)視窗版本
💻 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.,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA**********/// "liveMedia"// Copyright (c) 1996-2010 Live Networks, Inc.  All rights reserved.// A filter that converts a MPEG Transport Stream file - with corresponding index file// - to a corresponding Video Elementary Stream.  It also uses a "scale" parameter// to implement 'trick mode' (fast forward or reverse play, using I-frames) on// the video stream.// Implementation#include "MPEG2TransportStreamTrickModeFilter.hh"#include <ByteStreamFileSource.hh>// Define the following to be True if we want the output file to have the same frame rate as the original file.//    (Because the output file contains I-frames only, this means that each I-frame will appear in the output file//     several times, and therefore the output file's bitrate will be significantly higher than that of the original.)// Define the following to be False if we want the output file to include each I-frame no more than once.//    (This means that - except for high 'scale' values - both the output frame rate and the output bit rate//     will be less than that of the original.)#define KEEP_ORIGINAL_FRAME_RATE FalseMPEG2TransportStreamTrickModeFilter* MPEG2TransportStreamTrickModeFilter::createNew(UsageEnvironment& env, FramedSource* inputSource,	    MPEG2TransportStreamIndexFile* indexFile, int scale) {  return new MPEG2TransportStreamTrickModeFilter(env, inputSource, indexFile, scale);}MPEG2TransportStreamTrickModeFilter::MPEG2TransportStreamTrickModeFilter(UsageEnvironment& env, FramedSource* inputSource,				      MPEG2TransportStreamIndexFile* indexFile, int scale)  : FramedFilter(env, inputSource),    fHaveStarted(False), fIndexFile(indexFile), fScale(scale), fDirection(1),    fState(SKIPPING_FRAME), fFrameCount(0),    fNextIndexRecordNum(0), fNextTSPacketNum(0),    fCurrentTSPacketNum((unsigned long)(-1)), fUseSavedFrameNextTime(False) {  if (fScale < 0) { // reverse play    fScale = -fScale;    fDirection = -1;  }}MPEG2TransportStreamTrickModeFilter::~MPEG2TransportStreamTrickModeFilter() {}Boolean MPEG2TransportStreamTrickModeFilter::seekTo(unsigned long tsPacketNumber,						    unsigned long indexRecordNumber) {  seekToTransportPacket(tsPacketNumber);  fNextIndexRecordNum = indexRecordNumber;  return True;}#define isIFrameStart(type) ((type) == 0x81) // actually, a Video Sequence Header// This relies upon the fact that I-frames are always preceded by VSH and GOP#define isNonIFrameStart(type) ((type) == 0x83)void MPEG2TransportStreamTrickModeFilter::doGetNextFrame() {  //  fprintf(stderr, "#####DGNF1\n");  // If our client's buffer size is too small, then deliver  // a 0-byte 'frame', to tell it to process all of the data that it has  // already read, before asking for more data from us:  if (fMaxSize < TRANSPORT_PACKET_SIZE) {    fFrameSize = 0;    afterGetting(this);    return;  }  while (1) {    // Get the next record from our index file.    // This tells us the type of frame this data is, which Transport Stream packet    // (from the input source) the data comes from, and where in the Transport Stream    // packet it comes from:    u_int8_t recordType;    float recordPCR;    Boolean endOfIndexFile = False;    if (!fIndexFile->readIndexRecordValues(fNextIndexRecordNum,					   fDesiredTSPacketNum, fDesiredDataOffset,					   fDesiredDataSize, recordPCR,					   recordType)) {      // We ran off the end of the index file.  If we're not delivering a      // pre-saved frame, then handle this the same way as if the      // input Transport Stream source ended.      if (fState != DELIVERING_SAVED_FRAME) {	onSourceClosure1();	return;      }      endOfIndexFile = True;    } else if (!fHaveStarted) {      fFirstPCR = recordPCR;      fHaveStarted = True;    }    //    fprintf(stderr, "#####read index record %ld: ts %ld: %c, PCR %f\n", fNextIndexRecordNum, fDesiredTSPacketNum, isIFrameStart(recordType) ? 'I' : isNonIFrameStart(recordType) ? 'j' : 'x', recordPCR);    fNextIndexRecordNum      += (fState == DELIVERING_SAVED_FRAME) ? 1 : fDirection;    // Handle this index record, depending on the record type and our current state:    switch (fState) {    case SKIPPING_FRAME:    case SAVING_AND_DELIVERING_FRAME: {      //      if (fState == SKIPPING_FRAME) fprintf(stderr, "\tSKIPPING_FRAME\n"); else fprintf(stderr, "\tSAVING_AND_DELIVERING_FRAME\n");//#####      if (isIFrameStart(recordType)) {	// Save a record of this frame:	fSavedFrameIndexRecordStart = fNextIndexRecordNum - fDirection;	fUseSavedFrameNextTime = True;	//	fprintf(stderr, "\trecording\n");//#####	if ((fFrameCount++)%fScale == 0 && fUseSavedFrameNextTime) {	  // A frame is due now.	  fFrameCount = 1; // reset to avoid overflow	  if (fDirection > 0) {	    // Begin delivering this frame, as we're scanning it:	    fState = SAVING_AND_DELIVERING_FRAME;	    //	    fprintf(stderr, "\tdelivering\n");//#####	    fDesiredDataPCR = recordPCR; // use this frame's PCR	    attemptDeliveryToClient();	    return;	  } else {	    // Deliver this frame, then resume normal scanning:	    // (This relies on the index records having begun with an I-frame.)	    fState = DELIVERING_SAVED_FRAME;	    fSavedSequentialIndexRecordNum = fNextIndexRecordNum;	    fDesiredDataPCR = recordPCR;	    // use this frame's (not the saved frame's) PCR	    fNextIndexRecordNum = fSavedFrameIndexRecordStart;	    //	    fprintf(stderr, "\tbeginning delivery of saved frame\n");//#####	  }	} else {	  // No frame is needed now:	  fState = SKIPPING_FRAME;	}      } else if (isNonIFrameStart(recordType)) {	if ((fFrameCount++)%fScale == 0 && fUseSavedFrameNextTime) {	  // A frame is due now, so begin delivering the one that we had saved:	  // (This relies on the index records having begun with an I-frame.)	  fFrameCount = 1; // reset to avoid overflow	  fState = DELIVERING_SAVED_FRAME;	  fSavedSequentialIndexRecordNum = fNextIndexRecordNum;	  fDesiredDataPCR = recordPCR;	  // use this frame's (not the saved frame's) PCR	  fNextIndexRecordNum = fSavedFrameIndexRecordStart;	  //	  fprintf(stderr, "\tbeginning delivery of saved frame\n");//#####	} else {	  // No frame is needed now:	  fState = SKIPPING_FRAME;	}      } else {	// Not the start of a frame, but deliver it, if it's needed:	if (fState == SAVING_AND_DELIVERING_FRAME) {	  //	  fprintf(stderr, "\tdelivering\n");//#####	  fDesiredDataPCR = recordPCR; // use this frame's PCR	  attemptDeliveryToClient();	  return;	}      }      break;    }    case DELIVERING_SAVED_FRAME: {      //      fprintf(stderr, "\tDELIVERING_SAVED_FRAME\n");//#####      if (endOfIndexFile	  || (isIFrameStart(recordType)	      && fNextIndexRecordNum-1 != fSavedFrameIndexRecordStart)	  || isNonIFrameStart(recordType)) {	//	fprintf(stderr, "\tended delivery of saved frame\n");//#####	// We've reached the end of the saved frame, so revert to the	// original sequence of index records:	fNextIndexRecordNum = fSavedSequentialIndexRecordNum;	fUseSavedFrameNextTime = KEEP_ORIGINAL_FRAME_RATE;	fState = SKIPPING_FRAME;      } else {	// Continue delivering:	//	fprintf(stderr, "\tdelivering\n");//#####	attemptDeliveryToClient();	return;      }      break;    }    }  }}void MPEG2TransportStreamTrickModeFilter::doStopGettingFrames() {  FramedFilter::doStopGettingFrames();  fIndexFile->stopReading();}void MPEG2TransportStreamTrickModeFilter::attemptDeliveryToClient() {  if (fCurrentTSPacketNum == fDesiredTSPacketNum) {    //    fprintf(stderr, "\t\tdelivering ts %d:%d, %d bytes, PCR %f\n", fCurrentTSPacketNum, fDesiredDataOffset, fDesiredDataSize, fDesiredDataPCR);//#####    // We already have the Transport Packet that we want.  Deliver its data:    memmove(fTo, &fInputBuffer[fDesiredDataOffset], fDesiredDataSize);    fFrameSize = fDesiredDataSize;    float deliveryPCR = fDirection*(fDesiredDataPCR - fFirstPCR)/fScale;    if (deliveryPCR < 0.0) deliveryPCR = 0.0;    fPresentationTime.tv_sec = (unsigned long)deliveryPCR;    fPresentationTime.tv_usec      = (unsigned long)((deliveryPCR - fPresentationTime.tv_sec)*1000000.0f);    //    fprintf(stderr, "#####DGNF9\n");    afterGetting(this);  } else {    // Arrange to read the Transport Packet that we want:    readTransportPacket(fDesiredTSPacketNum);  }}void MPEG2TransportStreamTrickModeFilter::seekToTransportPacket(unsigned long tsPacketNum) {  if (tsPacketNum == fNextTSPacketNum) return; // we're already there  ByteStreamFileSource* tsFile = (ByteStreamFileSource*)fInputSource;  u_int64_t tsPacketNum64 = (u_int64_t)tsPacketNum;  tsFile->seekToByteAbsolute(tsPacketNum64*TRANSPORT_PACKET_SIZE);  fNextTSPacketNum = tsPacketNum;}void MPEG2TransportStreamTrickModeFilter::readTransportPacket(unsigned long tsPacketNum) {  seekToTransportPacket(tsPacketNum);  fInputSource->getNextFrame(fInputBuffer, TRANSPORT_PACKET_SIZE,			     afterGettingFrame, this,			     onSourceClosure, this);}void MPEG2TransportStreamTrickModeFilter::afterGettingFrame(void* clientData, unsigned frameSize,		    unsigned /*numTruncatedBytes*/,		    struct timeval presentationTime,		    unsigned /*durationInMicroseconds*/) {  MPEG2TransportStreamTrickModeFilter* filter = (MPEG2TransportStreamTrickModeFilter*)clientData;  filter->afterGettingFrame1(frameSize);}void MPEG2TransportStreamTrickModeFilter::afterGettingFrame1(unsigned frameSize) {  if (frameSize != TRANSPORT_PACKET_SIZE) {    // Treat this as if the input source ended:    onSourceClosure1();    return;  }  fCurrentTSPacketNum = fNextTSPacketNum; // i.e., the one that we just read  ++fNextTSPacketNum;  // Attempt deliver again:  attemptDeliveryToClient();}void MPEG2TransportStreamTrickModeFilter::onSourceClosure(void* clientData) {  MPEG2TransportStreamTrickModeFilter* filter = (MPEG2TransportStreamTrickModeFilter*)clientData;  filter->onSourceClosure1();}void MPEG2TransportStreamTrickModeFilter::onSourceClosure1() {  fIndexFile->stopReading();  FramedSource::handleClosure(this);}

⌨️ 快捷键说明

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