📄 mpeg4videostreamframer.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-2004 Live Networks, Inc. All rights reserved.// A filter that breaks up an MPEG-4 video elementary stream into// frames for:// - Visual Object Sequence (VS) Header + Visual Object (VO) Header// + Video Object Layer (VOL) Header// - Group of VOP (GOV) Header// - VOP frame// Implementation#include "MPEG4VideoStreamFramer.hh"#include "MPEGVideoStreamParser.hh"#include <string.h>////////// MPEG4VideoStreamParser definition //////////// An enum representing the current state of the parser:enum MPEGParseState { PARSING_VISUAL_OBJECT_SEQUENCE, PARSING_VISUAL_OBJECT_SEQUENCE_SEEN_CODE, PARSING_VISUAL_OBJECT, PARSING_VIDEO_OBJECT_LAYER, PARSING_GROUP_OF_VIDEO_OBJECT_PLANE, PARSING_VIDEO_OBJECT_PLANE, PARSING_VISUAL_OBJECT_SEQUENCE_END_CODE}; class MPEG4VideoStreamParser: public MPEGVideoStreamParser {public: MPEG4VideoStreamParser(MPEG4VideoStreamFramer* usingSource, FramedSource* inputSource); virtual ~MPEG4VideoStreamParser();private: // redefined virtual functions: virtual void flushInput(); virtual unsigned parse();private: MPEG4VideoStreamFramer* usingSource() { return (MPEG4VideoStreamFramer*)fUsingSource; } void setParseState(MPEGParseState parseState); unsigned parseVisualObjectSequence(Boolean haveSeenStartCode = False); unsigned parseVisualObject(); unsigned parseVideoObjectLayer(); unsigned parseGroupOfVideoObjectPlane(); unsigned parseVideoObjectPlane(); unsigned parseVisualObjectSequenceEndCode(); // These are used for parsing within an already-read frame: Boolean getNextFrameBit(u_int8_t& result); Boolean getNextFrameBits(unsigned numBits, u_int32_t& result); // Which are used by: void analyzeVOLHeader();private: MPEGParseState fCurrentParseState; unsigned fNumBitsSeenSoFar; // used by the getNextFrameBit*() routines u_int32_t vop_time_increment_resolution; unsigned fNumVTIRBits; // # of bits needed to count to "vop_time_increment_resolution" u_int8_t fixed_vop_rate; unsigned fixed_vop_time_increment; // used if 'fixed_vop_rate' is set unsigned fSecondsSinceLastTimeCode, fTotalTicksSinceLastTimeCode, fPrevNewTotalTicks; unsigned fPrevPictureCountDelta;};////////// MPEG4VideoStreamFramer implementation //////////MPEG4VideoStreamFramer*MPEG4VideoStreamFramer::createNew(UsageEnvironment& env, FramedSource* inputSource) { // Need to add source type checking here??? ##### return new MPEG4VideoStreamFramer(env, inputSource);}unsigned char* MPEG4VideoStreamFramer::getConfigBytes(unsigned& numBytes) const { numBytes = fNumConfigBytes; return fConfigBytes;}MPEG4VideoStreamFramer::MPEG4VideoStreamFramer(UsageEnvironment& env, FramedSource* inputSource, Boolean createParser) : MPEGVideoStreamFramer(env, inputSource), fProfileAndLevelIndication(0), fConfigBytes(NULL), fNumConfigBytes(0), fNewConfigBytes(NULL), fNumNewConfigBytes(0) { fParser = createParser ? new MPEG4VideoStreamParser(this, inputSource) : NULL;}MPEG4VideoStreamFramer::~MPEG4VideoStreamFramer() { delete[] fConfigBytes; delete[] fNewConfigBytes;}void MPEG4VideoStreamFramer::startNewConfig() { delete[] fNewConfigBytes; fNewConfigBytes = NULL; fNumNewConfigBytes = 0;}void MPEG4VideoStreamFramer::appendToNewConfig(unsigned char* newConfigBytes, unsigned numNewBytes) { // Allocate a new block of memory for the new config bytes: unsigned char* configNew = new unsigned char[fNumNewConfigBytes + numNewBytes]; // Copy the old, then the new, config bytes there: memmove(configNew, fNewConfigBytes, fNumNewConfigBytes); memmove(&configNew[fNumNewConfigBytes], newConfigBytes, numNewBytes); delete[] fNewConfigBytes; fNewConfigBytes = configNew; fNumNewConfigBytes += numNewBytes;}void MPEG4VideoStreamFramer::completeNewConfig() { delete fConfigBytes; fConfigBytes = fNewConfigBytes; fNewConfigBytes = NULL; fNumConfigBytes = fNumNewConfigBytes; fNumNewConfigBytes = 0;}Boolean MPEG4VideoStreamFramer::isMPEG4VideoStreamFramer() const { return True;}////////// MPEG4VideoStreamParser implementation //////////MPEG4VideoStreamParser::MPEG4VideoStreamParser(MPEG4VideoStreamFramer* usingSource, FramedSource* inputSource) : MPEGVideoStreamParser(usingSource, inputSource), fCurrentParseState(PARSING_VISUAL_OBJECT_SEQUENCE), vop_time_increment_resolution(0), fNumVTIRBits(0), fixed_vop_rate(0), fixed_vop_time_increment(0), fSecondsSinceLastTimeCode(0), fTotalTicksSinceLastTimeCode(0), fPrevNewTotalTicks(0), fPrevPictureCountDelta(1) {}MPEG4VideoStreamParser::~MPEG4VideoStreamParser() {}void MPEG4VideoStreamParser::setParseState(MPEGParseState parseState) { fCurrentParseState = parseState; MPEGVideoStreamParser::setParseState();}void MPEG4VideoStreamParser::flushInput() { fSecondsSinceLastTimeCode = 0; fTotalTicksSinceLastTimeCode = 0; fPrevNewTotalTicks = 0; fPrevPictureCountDelta = 1; StreamParser::flushInput(); if (fCurrentParseState != PARSING_VISUAL_OBJECT_SEQUENCE) { setParseState(PARSING_VISUAL_OBJECT_SEQUENCE); // later, change to GOV or VOP? ##### }}unsigned MPEG4VideoStreamParser::parse() { try { switch (fCurrentParseState) { case PARSING_VISUAL_OBJECT_SEQUENCE: { return parseVisualObjectSequence(); } case PARSING_VISUAL_OBJECT_SEQUENCE_SEEN_CODE: { return parseVisualObjectSequence(True); } case PARSING_VISUAL_OBJECT: { return parseVisualObject(); } case PARSING_VIDEO_OBJECT_LAYER: { return parseVideoObjectLayer(); } case PARSING_GROUP_OF_VIDEO_OBJECT_PLANE: { return parseGroupOfVideoObjectPlane(); } case PARSING_VIDEO_OBJECT_PLANE: { return parseVideoObjectPlane(); } case PARSING_VISUAL_OBJECT_SEQUENCE_END_CODE: { return parseVisualObjectSequenceEndCode(); } default: { return 0; // shouldn't happen } } } catch (int /*e*/) {#ifdef DEBUG fprintf(stderr, "MPEG4VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");#endif return 0; // the parsing got interrupted }}#define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0#define VISUAL_OBJECT_SEQUENCE_END_CODE 0x000001B1#define GROUP_VOP_START_CODE 0x000001B3#define VISUAL_OBJECT_START_CODE 0x000001B5#define VOP_START_CODE 0x000001B6unsigned MPEG4VideoStreamParser::parseVisualObjectSequence(Boolean haveSeenStartCode) {#ifdef DEBUG fprintf(stderr, "parsing VisualObjectSequence\n");#endif usingSource()->startNewConfig(); u_int32_t first4Bytes; if (!haveSeenStartCode) { while ((first4Bytes = test4Bytes()) != VISUAL_OBJECT_SEQUENCE_START_CODE) {#ifdef DEBUG fprintf(stderr, "ignoring non VS header: 0x%08x\n", first4Bytes);#endif get1Byte(); setParseState(PARSING_VISUAL_OBJECT_SEQUENCE); // ensures we progress over bad data } first4Bytes = get4Bytes(); } else { // We've already seen the start code first4Bytes = VISUAL_OBJECT_SEQUENCE_START_CODE; } save4Bytes(first4Bytes); // The next byte is the "profile_and_level_indication": u_int8_t pali = get1Byte();#ifdef DEBUG fprintf(stderr, "profile_and_level_indication: %02x\n", pali);#endif saveByte(pali); usingSource()->fProfileAndLevelIndication = pali; // Now, copy all bytes that we see, up until we reach // a VISUAL_OBJECT_START_CODE: u_int32_t next4Bytes = get4Bytes(); while (next4Bytes != VISUAL_OBJECT_START_CODE) { saveToNextCode(next4Bytes); } setParseState(PARSING_VISUAL_OBJECT); // Compute this frame's presentation time: usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); // This header forms part of the 'configuration' information: usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize()); return curFrameSize();}static inline Boolean isVideoObjectStartCode(u_int32_t code) { return code >= 0x00000100 && code <= 0x0000011F;}unsigned MPEG4VideoStreamParser::parseVisualObject() {#ifdef DEBUG fprintf(stderr, "parsing VisualObject\n");#endif // Note that we've already read the VISUAL_OBJECT_START_CODE save4Bytes(VISUAL_OBJECT_START_CODE); // Next, extract the "visual_object_type" from the next 1 or 2 bytes: u_int8_t nextByte = get1Byte(); saveByte(nextByte); Boolean is_visual_object_identifier = (nextByte&0x80) != 0; u_int8_t visual_object_type; if (is_visual_object_identifier) {#ifdef DEBUG fprintf(stderr, "visual_object_verid: 0x%x; visual_object_priority: 0x%x\n", (nextByte&0x78)>>3, (nextByte&0x07));#endif nextByte = get1Byte(); saveByte(nextByte); visual_object_type = (nextByte&0xF0)>>4; } else { visual_object_type = (nextByte&0x78)>>3; }#ifdef DEBUG fprintf(stderr, "visual_object_type: 0x%x\n", visual_object_type);#endif // At present, we support only the "Video ID" "visual_object_type" (1) if (visual_object_type != 1) { usingSource()->envir() << "MPEG4VideoStreamParser::parseVisualObject(): Warning: We don't handle visual_object_type " << visual_object_type << "\n"; } // Now, copy all bytes that we see, up until we reach // a video_object_start_code u_int32_t next4Bytes = get4Bytes(); while (!isVideoObjectStartCode(next4Bytes)) { saveToNextCode(next4Bytes); } save4Bytes(next4Bytes);#ifdef DEBUG fprintf(stderr, "saw a video_object_start_code: 0x%08x\n", next4Bytes);#endif setParseState(PARSING_VIDEO_OBJECT_LAYER); // Compute this frame's presentation time: usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); // This header forms part of the 'configuration' information: usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize()); return curFrameSize();}static inline Boolean isVideoObjectLayerStartCode(u_int32_t code) { return code >= 0x00000120 && code <= 0x0000012F;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -