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

📄 mpeg2indexfromtransportstream.cpp

📁 H.264 RTSP 串流(live 555)視窗版本
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/**********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 produces a sequence of I-frame indices from a MPEG-2 Transport Stream// Implementation#include "MPEG2IndexFromTransportStream.hh"////////// IndexRecord definition //////////enum RecordType {  RECORD_UNPARSED = 0,  RECORD_VSH = 1,  RECORD_GOP = 2,  RECORD_PIC_NON_IFRAME = 3, // includes slices  RECORD_PIC_IFRAME = 4, // includes slices  RECORD_JUNK};class IndexRecord {public:  IndexRecord(u_int8_t startOffset, u_int8_t size,	      unsigned long transportPacketNumber, float pcr);  virtual ~IndexRecord();  RecordType& recordType() { return fRecordType; }  void setFirstFlag() { fRecordType = (RecordType)(((u_int8_t)fRecordType) | 0x80); }  u_int8_t startOffset() const { return fStartOffset; }  u_int8_t& size() { return fSize; }  float pcr() const { return fPCR; }  unsigned long transportPacketNumber() const { return fTransportPacketNumber; }  IndexRecord* next() const { return fNext; }  void addAfter(IndexRecord* prev);  void unlink();private:  // Index records are maintained in a doubly-linked list:  IndexRecord* fNext;  IndexRecord* fPrev;  RecordType fRecordType;  u_int8_t fStartOffset; // within the Transport Stream packet  u_int8_t fSize; // in bytes, following "fStartOffset".  // Note: fStartOffset + fSize <= TRANSPORT_PACKET_SIZE  float fPCR;  unsigned long fTransportPacketNumber;};#ifdef DEBUGstatic char const* recordTypeStr[] = {  "UNPARSED",  "VSH",  "GOP",  "PIC(non-I-frame)",  "PIC(I-frame)",  "JUNK"};UsageEnvironment& operator<<(UsageEnvironment& env, IndexRecord& r) {  return env << "[" << ((r.recordType()&0x80) != 0 ? "1" : "")	     << recordTypeStr[r.recordType()&0x7F] << ":"	     << (unsigned)r.transportPacketNumber() << ":" << r.startOffset()	     << "(" << r.size() << ")@" << r.pcr() << "]";}#endif////////// MPEG2IFrameIndexFromTransportStream implementation //////////MPEG2IFrameIndexFromTransportStream*MPEG2IFrameIndexFromTransportStream::createNew(UsageEnvironment& env,					       FramedSource* inputSource) {  return new MPEG2IFrameIndexFromTransportStream(env, inputSource);}// The largest expected frame size (in bytes):#define MAX_FRAME_SIZE 400000// Make our parse buffer twice as large as this, to ensure that at least one// complete frame will fit inside it:#define PARSE_BUFFER_SIZE (2*MAX_FRAME_SIZE)// The PID used for the PAT (as defined in the MPEG Transport Stream standard):#define PAT_PID 0MPEG2IFrameIndexFromTransportStream::MPEG2IFrameIndexFromTransportStream(UsageEnvironment& env,				      FramedSource* inputSource)  : FramedFilter(env, inputSource),    fInputTransportPacketCounter((unsigned)-1), fClosureNumber(0),    fLastContinuityCounter(~0),    fFirstPCR(0.0), fLastPCR(0.0), fHaveSeenFirstPCR(False),    fPMT_PID(0x10), fVideo_PID(0xE0), // default values    fParseBufferSize(PARSE_BUFFER_SIZE),    fParseBufferFrameStart(0), fParseBufferParseEnd(4), fParseBufferDataEnd(0),    fHeadIndexRecord(NULL), fTailIndexRecord(NULL) {  fParseBuffer = new unsigned char[fParseBufferSize];}MPEG2IFrameIndexFromTransportStream::~MPEG2IFrameIndexFromTransportStream() {  delete fHeadIndexRecord;  delete[] fParseBuffer;}void MPEG2IFrameIndexFromTransportStream::doGetNextFrame() {  // Begin by trying to deliver an index record (for an already-parsed frame)  // to the client:  if (deliverIndexRecord()) return;  // No more index records are left to deliver, so try to parse a new frame:  if (parseFrame()) { // success - try again    doGetNextFrame();    return;  }  // We need to read some more Transport Stream packets.  Check whether we have room:  if (fParseBufferSize - fParseBufferDataEnd < TRANSPORT_PACKET_SIZE) {    // There's no room left.  Compact the buffer, and check again:    compactParseBuffer();    if (fParseBufferSize - fParseBufferDataEnd < TRANSPORT_PACKET_SIZE) {      envir() << "ERROR: parse buffer full; increase MAX_FRAME_SIZE\n";      // Treat this as if the input source ended:      handleInputClosure1();      return;    }  }  // Arrange to read a new Transport Stream packet:  fInputSource->getNextFrame(fInputBuffer, sizeof fInputBuffer,			     afterGettingFrame, this,			     handleInputClosure, this);}void MPEG2IFrameIndexFromTransportStream::afterGettingFrame(void* clientData, unsigned frameSize,		    unsigned numTruncatedBytes,		    struct timeval presentationTime,		    unsigned durationInMicroseconds) {  MPEG2IFrameIndexFromTransportStream* source    = (MPEG2IFrameIndexFromTransportStream*)clientData;  source->afterGettingFrame1(frameSize, numTruncatedBytes,			     presentationTime, durationInMicroseconds);}void MPEG2IFrameIndexFromTransportStream::afterGettingFrame1(unsigned frameSize,		     unsigned numTruncatedBytes,		     struct timeval presentationTime,		     unsigned durationInMicroseconds) {  if (frameSize < TRANSPORT_PACKET_SIZE || fInputBuffer[0] != 0x47/*sync byte*/) {    if (fInputBuffer[0] != 0x47) {      envir() << "Bad TS sync byte: 0x" << fInputBuffer[0] << "\n";    }    // Handle this as if the source ended:    handleInputClosure1();    return;  }  ++fInputTransportPacketCounter;  // Figure out how much of this Transport Packet contains PES data:  u_int8_t adaptation_field_control = (fInputBuffer[3]&0x30)>>4;  u_int8_t totalHeaderSize    = adaptation_field_control == 1 ? 4 : 5 + fInputBuffer[4];  // Check for a PCR:  if (totalHeaderSize > 5 && (fInputBuffer[5]&0x10) != 0) {    // There's a PCR:    u_int32_t pcrBaseHigh      = (fInputBuffer[6]<<24)|(fInputBuffer[7]<<16)      |(fInputBuffer[8]<<8)|fInputBuffer[9];    float pcr = pcrBaseHigh/45000.0f;    if ((fInputBuffer[10]&0x80) != 0) pcr += 1/90000.0f; // add in low-bit (if set)    unsigned short pcrExt = ((fInputBuffer[10]&0x01)<<8) | fInputBuffer[11];    pcr += pcrExt/27000000.0f;    if (!fHaveSeenFirstPCR) {      fFirstPCR = pcr;      fHaveSeenFirstPCR = True;    }    fLastPCR = pcr;  }  // Get the PID from the packet, and check for special tables: the PAT and PMT:  u_int16_t PID = ((fInputBuffer[1]&0x1F)<<8) | fInputBuffer[2];  if (PID == PAT_PID) {    analyzePAT(&fInputBuffer[totalHeaderSize], TRANSPORT_PACKET_SIZE-totalHeaderSize);  } else if (PID == fPMT_PID) {    analyzePMT(&fInputBuffer[totalHeaderSize], TRANSPORT_PACKET_SIZE-totalHeaderSize);  }  // Ignore transport packets for non-video programs,  // or packets with no data, or packets that duplicate the previous packet:  u_int8_t continuity_counter = fInputBuffer[3]&0x0F;  if ((PID != fVideo_PID) ||      !(adaptation_field_control == 1  || adaptation_field_control == 3) ||      continuity_counter == fLastContinuityCounter) {    doGetNextFrame();    return;  }  fLastContinuityCounter = continuity_counter;  // Also, if this is the start of a PES packet, then skip over the PES header:  Boolean payload_unit_start_indicator = (fInputBuffer[1]&0x40) != 0;  //fprintf(stderr, "PUSI: %d\n", payload_unit_start_indicator);//#####  if (payload_unit_start_indicator) {    // Note: The following works only for MPEG-2 data #####    u_int8_t PES_header_data_length = fInputBuffer[totalHeaderSize+8];    //fprintf(stderr, "PES_header_data_length: %d\n", PES_header_data_length);//#####    totalHeaderSize += 9 + PES_header_data_length;    if (totalHeaderSize >= TRANSPORT_PACKET_SIZE) {      envir() << "Unexpectedly large PES header size: " << PES_header_data_length << "\n";      // Handle this as if the source ended:      handleInputClosure1();      return;    }  }  // The remaining data is Video Elementary Stream data.  Add it to our parse buffer:  unsigned vesSize = TRANSPORT_PACKET_SIZE - totalHeaderSize;  memmove(&fParseBuffer[fParseBufferDataEnd], &fInputBuffer[totalHeaderSize], vesSize);  fParseBufferDataEnd += vesSize;  // And add a new index record noting where it came from:  addToTail(new IndexRecord(totalHeaderSize, vesSize, fInputTransportPacketCounter,			    fLastPCR - fFirstPCR));  // Try again:  doGetNextFrame();}void MPEG2IFrameIndexFromTransportStream::handleInputClosure(void* clientData) {  MPEG2IFrameIndexFromTransportStream* source    = (MPEG2IFrameIndexFromTransportStream*)clientData;  source->handleInputClosure1();}#define VIDEO_SEQUENCE_START_CODE 0xB3		// MPEG-1 or 2#define VISUAL_OBJECT_SEQUENCE_START_CODE 0xB0	// MPEG-4#define GROUP_START_CODE 0xB8			// MPEG-1 or 2#define GROUP_VOP_START_CODE 0xB3		// MPEG-4#define PICTURE_START_CODE 0x00			// MPEG-1 or 2#define VOP_START_CODE 0xB6			// MPEG-4void MPEG2IFrameIndexFromTransportStream::handleInputClosure1() {  if (++fClosureNumber == 1 && fParseBufferDataEnd > fParseBufferFrameStart      && fParseBufferDataEnd <= fParseBufferSize - 4) {    // This is the first time we saw EOF, and there's still data remaining to be    // parsed.  Hack: Append a Picture Header code to the end of the unparsed    // data, and try again.  This should use up all of the unparsed data.    fParseBuffer[fParseBufferDataEnd++] = 0;    fParseBuffer[fParseBufferDataEnd++] = 0;    fParseBuffer[fParseBufferDataEnd++] = 1;    fParseBuffer[fParseBufferDataEnd++] = PICTURE_START_CODE;    // Try again:    doGetNextFrame();  } else {    // Handle closure in the regular way:    FramedSource::handleClosure(this);  }}void MPEG2IFrameIndexFromTransportStream::analyzePAT(unsigned char* pkt, unsigned size) {  // Get the PMT_PID:  while (size >= 17) { // The table is large enough    u_int16_t program_number = (pkt[9]<<8) | pkt[10];    if (program_number != 0) {      fPMT_PID = ((pkt[11]&0x1F)<<8) | pkt[12];      return;    }    pkt += 4; size -= 4;  }}void MPEG2IFrameIndexFromTransportStream::analyzePMT(unsigned char* pkt, unsigned size) {  // Scan the "elementary_PID"s in the map, until we see the first video stream.  // First, get the "section_length", to get the table's size:

⌨️ 快捷键说明

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