📄 mpeg2indexfromtransportstream.cpp
字号:
u_int16_t section_length = ((pkt[2]&0x0F)<<8) | pkt[3]; if ((unsigned)(4+section_length) < size) size = (4+section_length); // Then, skip any descriptors following the "program_info_length": if (size < 22) return; // not enough data unsigned program_info_length = ((pkt[11]&0x0F)<<8) | pkt[12]; pkt += 13; size -= 13; if (size < program_info_length) return; // not enough data pkt += program_info_length; size -= program_info_length; // Look at each ("stream_type","elementary_PID") pair, looking for a video stream // ("stream_type" == 1 or 2): while (size >= 9) { u_int8_t stream_type = pkt[0]; u_int16_t elementary_PID = ((pkt[1]&0x1F)<<8) | pkt[2]; if (stream_type == 1 || stream_type == 2) { fVideo_PID = elementary_PID; return; } u_int16_t ES_info_length = ((pkt[3]&0x0F)<<8) | pkt[4]; pkt += 5; size -= 5; if (size < ES_info_length) return; // not enough data pkt += ES_info_length; size -= ES_info_length; }}Boolean MPEG2IFrameIndexFromTransportStream::deliverIndexRecord() { IndexRecord* head = fHeadIndexRecord; if (head == NULL) return False; // Check whether the head record has been parsed yet: if (head->recordType() == RECORD_UNPARSED) return False; // Remove the head record (the one whose data we'll be delivering): IndexRecord* next = head->next(); head->unlink(); if (next == head) { fHeadIndexRecord = fTailIndexRecord = NULL; } else { fHeadIndexRecord = next; } if (head->recordType() == RECORD_JUNK) { // Don't actually deliver the data to the client: delete head; return True; } // Deliver data from the head record:#ifdef DEBUG envir() << "delivering: " << *head << "\n";#endif if (fMaxSize < 11) { fFrameSize = 0; } else { fTo[0] = (u_int8_t)(head->recordType()); fTo[1] = head->startOffset(); fTo[2] = head->size(); // Deliver the PCR, as 24 bits (integer part; little endian) + 8 bits (fractional part) float pcr = head->pcr(); unsigned pcr_int = (unsigned)pcr; u_int8_t pcr_frac = (u_int8_t)(256*(pcr-pcr_int)); fTo[3] = (unsigned char)(pcr_int); fTo[4] = (unsigned char)(pcr_int>>8); fTo[5] = (unsigned char)(pcr_int>>16); fTo[6] = (unsigned char)(pcr_frac); // Deliver the transport packet number (in little-endian order): unsigned long tpn = head->transportPacketNumber(); fTo[7] = (unsigned char)(tpn); fTo[8] = (unsigned char)(tpn>>8); fTo[9] = (unsigned char)(tpn>>16); fTo[10] = (unsigned char)(tpn>>24); fFrameSize = 11; } // Free the (former) head record (as we're now done with it): delete head; // Complete delivery to the client: afterGetting(this); return True;}Boolean MPEG2IFrameIndexFromTransportStream::parseFrame() { // At this point, we have a queue of >=0 (unparsed) index records, representing // the data in the parse buffer from "fParseBufferFrameStart" // to "fParseBufferDataEnd". We now parse through this data, looking for // a complete 'frame' (where a 'frame', in this case, means // a Video Sequence Header, GOP Header, Picture Header, or Slice). // Inspect the frame's initial 4-byte code, to make sure it starts with a system code: if (fParseBufferDataEnd-fParseBufferFrameStart < 4) return False; // not enough data unsigned numInitialBadBytes = 0; unsigned char const* p = &fParseBuffer[fParseBufferFrameStart]; if (!(p[0] == 0 && p[1] == 0 && p[2] == 1)) { // There's no system code at the beginning. Parse until we find one: if (fParseBufferParseEnd == fParseBufferFrameStart + 4) { // Start parsing from the beginning of the frame data: fParseBufferParseEnd = fParseBufferFrameStart; } unsigned char nextCode; if (!parseToNextCode(nextCode)) return False; numInitialBadBytes = fParseBufferParseEnd - fParseBufferFrameStart; //fprintf(stderr, "#####numInitialBadBytes: 0x%x\n", numInitialBadBytes); fParseBufferFrameStart = fParseBufferParseEnd; fParseBufferParseEnd += 4; // skip over the code that we just saw p = &fParseBuffer[fParseBufferFrameStart]; } unsigned char curCode = p[3]; RecordType curRecordType; unsigned char nextCode; switch (curCode) { case VIDEO_SEQUENCE_START_CODE: case VISUAL_OBJECT_SEQUENCE_START_CODE: { curRecordType = RECORD_VSH; while (1) { if (!parseToNextCode(nextCode)) return False; if (nextCode == GROUP_START_CODE || /*nextCode == GROUP_VOP_START_CODE ||*/ nextCode == PICTURE_START_CODE || nextCode == VOP_START_CODE) break; fParseBufferParseEnd += 4; // skip over the code that we just saw } break; } case GROUP_START_CODE: /*case GROUP_VOP_START_CODE:*/ { curRecordType = RECORD_GOP; while (1) { if (!parseToNextCode(nextCode)) return False; if (nextCode == PICTURE_START_CODE || nextCode == VOP_START_CODE) break; fParseBufferParseEnd += 4; // skip over the code that we just saw } break; } default: { // picture (including slices) curRecordType = RECORD_PIC_NON_IFRAME; // may get changed to IFRAME later while (1) { if (!parseToNextCode(nextCode)) return False; if (nextCode == VIDEO_SEQUENCE_START_CODE || nextCode == VISUAL_OBJECT_SEQUENCE_START_CODE || nextCode == GROUP_START_CODE || nextCode == GROUP_VOP_START_CODE || nextCode == PICTURE_START_CODE || nextCode == VOP_START_CODE) break; fParseBufferParseEnd += 4; // skip over the code that we just saw } break; } } if (curRecordType == RECORD_PIC_NON_IFRAME) { if (curCode == VOP_START_CODE) { // MPEG-4 //fprintf(stderr, "#####parseFrame()1(4): 0x%x, 0x%x\n", curCode, fParseBuffer[fParseBufferFrameStart+4]&0xC0); if ((fParseBuffer[fParseBufferFrameStart+4]&0xC0) == 0) { // This is actually an I-frame. Note it as such: curRecordType = RECORD_PIC_IFRAME; } } else { // MPEG-1 or 2 //fprintf(stderr, "#####parseFrame()1(!4): 0x%x, 0x%x\n", curCode, fParseBuffer[fParseBufferFrameStart+5]&0x38); if ((fParseBuffer[fParseBufferFrameStart+5]&0x38) == 0x08) { // This is actually an I-frame. Note it as such: curRecordType = RECORD_PIC_IFRAME; } } } // There is now a parsed 'frame', from "fParseBufferFrameStart" // to "fParseBufferParseEnd". Tag the corresponding index records to note this: unsigned frameSize = fParseBufferParseEnd - fParseBufferFrameStart + numInitialBadBytes;#ifdef DEBUG envir() << "parsed " << recordTypeStr[curRecordType] << "; length " << frameSize << "\n";#endif for (IndexRecord* r = fHeadIndexRecord; ; r = r->next()) { if (numInitialBadBytes >= r->size()) { r->recordType() = RECORD_JUNK; numInitialBadBytes -= r->size(); } else { r->recordType() = curRecordType; } if (r == fHeadIndexRecord) r->setFirstFlag(); // indicates that this is the first record for this frame if (r->size() > frameSize) { // This record contains extra data that's not part of the frame. // Shorten this record, and move the extra data to a new record // that comes afterwards: u_int8_t newOffset = r->startOffset() + frameSize; u_int8_t newSize = r->size() - frameSize; r->size() = frameSize;#ifdef DEBUG envir() << "tagged record (modified): " << *r << "\n";#endif IndexRecord* newRecord = new IndexRecord(newOffset, newSize, r->transportPacketNumber(), r->pcr()); newRecord->addAfter(r); if (fTailIndexRecord == r) fTailIndexRecord = newRecord;#ifdef DEBUG envir() << "added extra record: " << *newRecord << "\n";#endif } else {#ifdef DEBUG envir() << "tagged record: " << *r << "\n";#endif } frameSize -= r->size(); if (frameSize == 0) break; if (r == fTailIndexRecord) { // this shouldn't happen envir() << "!!!!!Internal consistency error!!!!!\n"; return False; } } // Finally, update our parse state (to skip over the now-parsed data): fParseBufferFrameStart = fParseBufferParseEnd; fParseBufferParseEnd += 4; // to skip over the next code (that we found) return True;}Boolean MPEG2IFrameIndexFromTransportStream::parseToNextCode(unsigned char& nextCode) { unsigned char const* p = &fParseBuffer[fParseBufferParseEnd]; unsigned char const* end = &fParseBuffer[fParseBufferDataEnd]; while (p <= end-4) { if (p[2] > 1) p += 3; // common case (optimized) else if (p[2] == 0) ++p; else if (p[0] == 0 && p[1] == 0) { // && p[2] == 1 // We found a code here: nextCode = p[3]; fParseBufferParseEnd = p - &fParseBuffer[0]; // where we've gotten to return True; } else p += 3; } fParseBufferParseEnd = p - &fParseBuffer[0]; // where we've gotten to return False; // no luck this time}void MPEG2IFrameIndexFromTransportStream::compactParseBuffer() {#ifdef DEBUG envir() << "Compacting parse buffer: [" << fParseBufferFrameStart << "," << fParseBufferParseEnd << "," << fParseBufferDataEnd << "]";#endif memmove(&fParseBuffer[0], &fParseBuffer[fParseBufferFrameStart], fParseBufferDataEnd - fParseBufferFrameStart); fParseBufferDataEnd -= fParseBufferFrameStart; fParseBufferParseEnd -= fParseBufferFrameStart; fParseBufferFrameStart = 0;#ifdef DEBUG envir() << "-> [" << fParseBufferFrameStart << "," << fParseBufferParseEnd << "," << fParseBufferDataEnd << "]\n";#endif}void MPEG2IFrameIndexFromTransportStream::addToTail(IndexRecord* newIndexRecord) {#ifdef DEBUG envir() << "adding new: " << *newIndexRecord << "\n";#endif if (fTailIndexRecord == NULL) { fHeadIndexRecord = fTailIndexRecord = newIndexRecord; } else { newIndexRecord->addAfter(fTailIndexRecord); fTailIndexRecord = newIndexRecord; }}////////// IndexRecord implementation //////////IndexRecord::IndexRecord(u_int8_t startOffset, u_int8_t size, unsigned long transportPacketNumber, float pcr) : fNext(this), fPrev(this), fRecordType(RECORD_UNPARSED), fStartOffset(startOffset), fSize(size), fPCR(pcr), fTransportPacketNumber(transportPacketNumber) {}IndexRecord::~IndexRecord() { IndexRecord* nextRecord = next(); unlink(); if (nextRecord != this) delete nextRecord;}void IndexRecord::addAfter(IndexRecord* prev) { fNext = prev->fNext; fPrev = prev; prev->fNext->fPrev = this; prev->fNext = this;}void IndexRecord::unlink() { fNext->fPrev = fPrev; fPrev->fNext = fNext; fNext = fPrev = this;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -