📄 mpeg1or2demux.cpp
字号:
void MPEGProgramStreamParser::parsePackHeader() {#ifdef DEBUG fprintf(stderr, "parsing pack header\n"); fflush(stderr);#endif unsigned first4Bytes; while (1) { first4Bytes = test4Bytes(); // We're supposed to have a pack header here, but check also for // a system header or a PES packet, just in case: if (first4Bytes == PACK_START_CODE) { skipBytes(4); break; } else if (first4Bytes == SYSTEM_HEADER_START_CODE) {#ifdef DEBUG fprintf(stderr, "found system header instead of pack header\n");#endif setParseState(PARSING_SYSTEM_HEADER); return; } else if (isPacketStartCode(first4Bytes)) {#ifdef DEBUG fprintf(stderr, "found packet start code 0x%02x instead of pack header\n", first4Bytes);#endif setParseState(PARSING_PES_PACKET); return; } setParseState(PARSING_PACK_HEADER); // ensures we progress over bad data if ((first4Bytes&0xFF) > 1) { // a system code definitely doesn't start here skipBytes(4); } else { skipBytes(1); } } // The size of the pack header differs depending on whether it's // MPEG-1 or MPEG-2. The next byte tells us this: unsigned char nextByte = get1Byte(); MPEG1or2Demux::SCR& scr = fUsingSource->fLastSeenSCR; // alias if ((nextByte&0xF0) == 0x20) { // MPEG-1 fUsingSource->fMPEGversion = 1; scr.highBit = (nextByte&0x08)>>3; scr.remainingBits = (nextByte&0x06)<<29; unsigned next4Bytes = get4Bytes(); scr.remainingBits |= (next4Bytes&0xFFFE0000)>>2; scr.remainingBits |= (next4Bytes&0x0000FFFE)>>1; scr.extension = 0; scr.isValid = True; skipBits(24);#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS) fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x", scr.highBit); fprintf(stderr, "%08x\n", scr.remainingBits);#endif } else if ((nextByte&0xC0) == 0x40) { // MPEG-2 fUsingSource->fMPEGversion = 2; scr.highBit = (nextByte&0x20)>>5; scr.remainingBits = (nextByte&0x18)<<27; scr.remainingBits |= (nextByte&0x03)<<28; unsigned next4Bytes = get4Bytes(); scr.remainingBits |= (next4Bytes&0xFFF80000)>>4; scr.remainingBits |= (next4Bytes&0x0003FFF8)>>3; scr.extension = (next4Bytes&0x00000003)<<7; next4Bytes = get4Bytes(); scr.extension |= (next4Bytes&0xFE000000)>>25; scr.isValid = True; skipBits(5);#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS) fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x", scr.highBit); fprintf(stderr, "%08x\n", scr.remainingBits); fprintf(stderr, "pack hdr system_clock_reference_extension: 0x%03x\n", scr.extension);#endif unsigned char pack_stuffing_length = getBits(3); skipBytes(pack_stuffing_length); } else { // unknown fUsingSource->envir() << "StreamParser::parsePack() saw strange byte " << (void*)nextByte << " following pack_start_code\n"; } // Check for a System Header next: setParseState(PARSING_SYSTEM_HEADER);} void MPEGProgramStreamParser::parseSystemHeader() {#ifdef DEBUG fprintf(stderr, "parsing system header\n"); fflush(stderr);#endif unsigned next4Bytes = test4Bytes(); if (next4Bytes != SYSTEM_HEADER_START_CODE) { // The system header was optional. Look for a PES Packet instead: setParseState(PARSING_PES_PACKET); return; } #ifdef DEBUG fprintf(stderr, "saw system_header_start_code\n"); fflush(stderr);#endif skipBytes(4); // we've already seen the system_header_start_code unsigned short remaining_header_length = get2Bytes(); // According to the MPEG-1 and MPEG-2 specs, "remaining_header_length" should be // at least 6 bytes. Check this now: if (remaining_header_length < 6) { fUsingSource->envir() << "StreamParser::parseSystemHeader(): saw strange header_length: " << remaining_header_length << " < 6\n"; } skipBytes(remaining_header_length); // Check for a PES Packet next: setParseState(PARSING_PES_PACKET);}#define private_stream_1 0xBD#define private_stream_2 0xBF// A test for stream ids that are exempt from normal PES packet header parsingBoolean MPEGProgramStreamParser::isSpecialStreamId(unsigned char stream_id) const { if (stream_id == RAW_PES) return True; // hack if (fUsingSource->fMPEGversion == 1) { return stream_id == private_stream_2; } else { // assume MPEG-2 if (stream_id <= private_stream_2) { return stream_id != private_stream_1; } else if ((stream_id&0xF0) == 0xF0) { unsigned char lower4Bits = stream_id&0x0F; return lower4Bits <= 2 || lower4Bits == 0x8 || lower4Bits == 0xF; } else { return False; } }}#define READER_NOT_READY 2 unsigned char MPEGProgramStreamParser::parsePESPacket() {#ifdef DEBUG fprintf(stderr, "parsing PES packet\n"); fflush(stderr);#endif unsigned next4Bytes = test4Bytes(); if (!isPacketStartCode(next4Bytes)) { // The PES Packet was optional. Look for a Pack Header instead: setParseState(PARSING_PACK_HEADER); return 0; } #ifdef DEBUG fprintf(stderr, "saw packet_start_code_prefix\n"); fflush(stderr);#endif skipBytes(3); // we've already seen the packet_start_code_prefix unsigned char stream_id = get1Byte();#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) unsigned char streamNum = stream_id; char* streamTypeStr; if ((stream_id&0xE0) == 0xC0) { streamTypeStr = "audio"; streamNum = stream_id&~0xE0; } else if ((stream_id&0xF0) == 0xE0) { streamTypeStr = "video"; streamNum = stream_id&~0xF0; } else if (stream_id == 0xbc) { streamTypeStr = "reserved"; } else if (stream_id == 0xbd) { streamTypeStr = "private_1"; } else if (stream_id == 0xbe) { streamTypeStr = "padding"; } else if (stream_id == 0xbf) { streamTypeStr = "private_2"; } else { streamTypeStr = "unknown"; }#endif#ifdef DEBUG static unsigned frameCount = 1; fprintf(stderr, "%d, saw %s stream: 0x%02x\n", frameCount, streamTypeStr, streamNum); fflush(stderr);#endif unsigned short PES_packet_length = get2Bytes();#ifdef DEBUG fprintf(stderr, "PES_packet_length: %d\n", PES_packet_length); fflush(stderr);#endif // Parse over the rest of the header, until we get to the packet data itself. // This varies depending upon the MPEG version: if (fUsingSource->fOutput[RAW_PES].isPotentiallyReadable) { // Hack: We've been asked to return raw PES packets, for every stream: stream_id = RAW_PES; } unsigned savedParserOffset = curOffset();#ifdef DEBUG_TIMESTAMPS unsigned char pts_highBit = 0; unsigned pts_remainingBits = 0; unsigned char dts_highBit = 0; unsigned dts_remainingBits = 0;#endif if (fUsingSource->fMPEGversion == 1) { if (!isSpecialStreamId(stream_id)) { unsigned char nextByte; while ((nextByte = get1Byte()) == 0xFF) { // stuffing_byte } if ((nextByte&0xC0) == 0x40) { // '01' skipBytes(1); nextByte = get1Byte(); } if ((nextByte&0xF0) == 0x20) { // '0010'#ifdef DEBUG_TIMESTAMPS pts_highBit = (nextByte&0x08)>>3; pts_remainingBits = (nextByte&0x06)<<29; unsigned next4Bytes = get4Bytes(); pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;#else skipBytes(4);#endif } else if ((nextByte&0xF0) == 0x30) { // '0011'#ifdef DEBUG_TIMESTAMPS pts_highBit = (nextByte&0x08)>>3; pts_remainingBits = (nextByte&0x06)<<29; unsigned next4Bytes = get4Bytes(); pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; nextByte = get1Byte(); dts_highBit = (nextByte&0x08)>>3; dts_remainingBits = (nextByte&0x06)<<29; next4Bytes = get4Bytes(); dts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; dts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;#else skipBytes(9);#endif } } } else { // assume MPEG-2 if (!isSpecialStreamId(stream_id)) { // Fields in the next 3 bytes determine the size of the rest: unsigned next3Bytes = getBits(24);#ifdef DEBUG_TIMESTAMPS unsigned char PTS_DTS_flags = (next3Bytes&0x00C000)>>14;#endif#ifdef undef unsigned char ESCR_flag = (next3Bytes&0x002000)>>13; unsigned char ES_rate_flag = (next3Bytes&0x001000)>>12; unsigned char DSM_trick_mode_flag = (next3Bytes&0x000800)>>11;#endif unsigned char PES_header_data_length = (next3Bytes&0x0000FF);#ifdef DEBUG fprintf(stderr, "PES_header_data_length: 0x%02x\n", PES_header_data_length); fflush(stderr);#endif#ifdef DEBUG_TIMESTAMPS if (PTS_DTS_flags == 0x2 && PES_header_data_length >= 5) { unsigned char nextByte = get1Byte(); pts_highBit = (nextByte&0x08)>>3; pts_remainingBits = (nextByte&0x06)<<29; unsigned next4Bytes = get4Bytes(); pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; skipBytes(PES_header_data_length-5); } else if (PTS_DTS_flags == 0x3 && PES_header_data_length >= 10) { unsigned char nextByte = get1Byte(); pts_highBit = (nextByte&0x08)>>3; pts_remainingBits = (nextByte&0x06)<<29; unsigned next4Bytes = get4Bytes(); pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; nextByte = get1Byte(); dts_highBit = (nextByte&0x08)>>3; dts_remainingBits = (nextByte&0x06)<<29; next4Bytes = get4Bytes(); dts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; dts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; skipBytes(PES_header_data_length-10); }#else skipBytes(PES_header_data_length);#endif } }#ifdef DEBUG_TIMESTAMPS fprintf(stderr, "%s stream, ", streamTypeStr); fprintf(stderr, "packet presentation_time_stamp: 0x%x", pts_highBit); fprintf(stderr, "%08x\n", pts_remainingBits); fprintf(stderr, "\t\tpacket decoding_time_stamp: 0x%x", dts_highBit); fprintf(stderr, "%08x\n", dts_remainingBits);#endif // The rest of the packet will be the "PES_packet_data_byte"s // Make sure that "PES_packet_length" was consistent with where we are now: unsigned char acquiredStreamIdTag = 0; unsigned currentParserOffset = curOffset(); unsigned bytesSkipped = currentParserOffset - savedParserOffset; if (stream_id == RAW_PES) { restoreSavedParserState(); // so we deliver from the beginning of the PES packet PES_packet_length += 6; // to include the whole of the PES packet bytesSkipped = 0; } if (PES_packet_length < bytesSkipped) { fUsingSource->envir() << "StreamParser::parsePESPacket(): saw inconsistent PES_packet_length " << PES_packet_length << " < " << bytesSkipped << "\n"; } else { PES_packet_length -= bytesSkipped;#ifdef DEBUG unsigned next4Bytes = test4Bytes(); #endif // Check whether our using source is interested in this stream type. // If so, deliver the frame to him: MPEG1or2Demux::OutputDescriptor_t& out = fUsingSource->fOutput[stream_id]; if (out.isCurrentlyAwaitingData) { unsigned numBytesToCopy; if (PES_packet_length > out.maxSize) { fUsingSource->envir() << "MPEGProgramStreamParser::parsePESPacket() error: PES_packet_length (" << PES_packet_length << ") exceeds max frame size asked for (" << out.maxSize << ")\n"; numBytesToCopy = out.maxSize; } else { numBytesToCopy = PES_packet_length; } getBytes(out.to, numBytesToCopy); out.frameSize = numBytesToCopy;#ifdef DEBUG fprintf(stderr, "%d, %d bytes of PES_packet_data (out.maxSize: %d); first 4 bytes: 0x%08x\n", frameCount, numBytesToCopy, out.maxSize, next4Bytes); fflush(stderr);#endif // set out.presentationTime later ##### acquiredStreamIdTag = stream_id; PES_packet_length -= numBytesToCopy; } else if (out.isCurrentlyActive) { // Someone has been reading this stream, but isn't right now. // We can't deliver this frame until he asks for it, so punt for now. // The next time he asks for a frame, he'll get it.#ifdef DEBUG fprintf(stderr, "%d, currently undeliverable PES data; first 4 bytes: 0x%08x - currently undeliverable!\n", frameCount, next4Bytes); fflush(stderr);#endif restoreSavedParserState(); // so we read from the beginning next time fUsingSource->fHaveUndeliveredData = True; throw READER_NOT_READY; } else if (out.isPotentiallyReadable && out.savedDataTotalSize + PES_packet_length < 1000000 /*limit*/) { // Someone is interested in this stream, but hasn't begun reading it yet. // Save this data, so that the reader will get it when he later asks for it. unsigned char* buf = new unsigned char[PES_packet_length]; getBytes(buf, PES_packet_length); MPEG1or2Demux::OutputDescriptor::SavedData* savedData = new MPEG1or2Demux::OutputDescriptor::SavedData(buf, PES_packet_length); if (out.savedDataHead == NULL) { out.savedDataHead = out.savedDataTail = savedData; } else { out.savedDataTail->next = savedData; out.savedDataTail = savedData; } out.savedDataTotalSize += PES_packet_length; PES_packet_length = 0; } skipBytes(PES_packet_length); } // Check for another PES Packet next: setParseState(PARSING_PES_PACKET);#ifdef DEBUG ++frameCount;#endif return acquiredStreamIdTag;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -