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

📄 mpeg4videostreamframer.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 2 页
字号:
Boolean MPEG4VideoStreamParser::getNextFrameBit(u_int8_t& result) {  if (fNumBitsSeenSoFar/8 >= curFrameSize()) return False;  u_int8_t nextByte = fStartOfFrame[fNumBitsSeenSoFar/8];  result = (nextByte>>(7-fNumBitsSeenSoFar%8))&1;  ++fNumBitsSeenSoFar;  return True;}Boolean MPEG4VideoStreamParser::getNextFrameBits(unsigned numBits,						 u_int32_t& result) {  result = 0;  for (unsigned i = 0; i < numBits; ++i) {    u_int8_t nextBit;    if (!getNextFrameBit(nextBit)) return False;    result = (result<<1)|nextBit;  }  return True;}void MPEG4VideoStreamParser::analyzeVOLHeader() {  // Extract timing information (in particular,  // "vop_time_increment_resolution") from the VOL Header:  fNumBitsSeenSoFar = 41;  do {    u_int8_t is_object_layer_identifier;    if (!getNextFrameBit(is_object_layer_identifier)) break;    if (is_object_layer_identifier) fNumBitsSeenSoFar += 7;    u_int32_t aspect_ratio_info;    if (!getNextFrameBits(4, aspect_ratio_info)) break;    if (aspect_ratio_info == 15 /*extended_PAR*/) fNumBitsSeenSoFar += 16;    u_int8_t vol_control_parameters;    if (!getNextFrameBit(vol_control_parameters)) break;    if (vol_control_parameters) {      fNumBitsSeenSoFar += 3; // chroma_format; low_delay      u_int8_t vbw_parameters;      if (!getNextFrameBit(vbw_parameters)) break;      if (vbw_parameters) fNumBitsSeenSoFar += 79;    }    fNumBitsSeenSoFar += 2; // video_object_layer_shape    u_int8_t marker_bit;    if (!getNextFrameBit(marker_bit)) break;    if (marker_bit != 1) { // sanity check      usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): marker_bit 1 not set!\n";      break;    }    if (!getNextFrameBits(16, vop_time_increment_resolution)) break;#ifdef DEBUG    fprintf(stderr, "vop_time_increment_resolution: %d\n", vop_time_increment_resolution);#endif    if (vop_time_increment_resolution == 0) {      usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): vop_time_increment_resolution is zero!\n";      break;    }    // Compute how many bits are necessary to represent this:    fNumVTIRBits = 0;    for (unsigned test = vop_time_increment_resolution; test>0; test /= 2) {      ++fNumVTIRBits;    }    if (!getNextFrameBit(marker_bit)) break;    if (marker_bit != 1) { // sanity check      usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): marker_bit 2 not set!\n";      break;    }    if (!getNextFrameBit(fixed_vop_rate)) break;    if (fixed_vop_rate) {      // Get the following "fixed_vop_time_increment":      if (!getNextFrameBits(fNumVTIRBits, fixed_vop_time_increment)) break;#ifdef DEBUG      fprintf(stderr, "fixed_vop_time_increment: %d\n", fixed_vop_time_increment);      if (fixed_vop_time_increment == 0) {	usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): fixed_vop_time_increment is zero!\n";      }#endif    }    // Use "vop_time_increment_resolution" as the 'frame rate'    // (really, 'tick rate'):    usingSource()->fFrameRate = (double)vop_time_increment_resolution;#ifdef DEBUG    fprintf(stderr, "fixed_vop_rate: %d; 'frame' (really tick) rate: %f\n", fixed_vop_rate, usingSource()->fFrameRate);#endif    return;  } while (0);  if (fNumBitsSeenSoFar/8 >= curFrameSize()) {    char errMsg[200];    sprintf(errMsg, "Not enough bits in VOL header: %d/8 >= %d\n", fNumBitsSeenSoFar, curFrameSize());    usingSource()->envir() << errMsg;  }}unsigned MPEG4VideoStreamParser::parseVideoObjectLayer() {#ifdef DEBUG  fprintf(stderr, "parsing VideoObjectLayer\n");#endif  // The first 4 bytes must be a "video_object_layer_start_code".  // If not, this is a 'short video header', which we currently  // don't support:  u_int32_t next4Bytes = get4Bytes();  if (!isVideoObjectLayerStartCode(next4Bytes)) {    usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectLayer(): This appears to be a 'short video header', which we current don't support\n";  }  // Now, copy all bytes that we see, up until we reach  // a GROUP_VOP_START_CODE or a VOP_START_CODE:  do {    saveToNextCode(next4Bytes);  } while (next4Bytes != GROUP_VOP_START_CODE	   && next4Bytes != VOP_START_CODE);    analyzeVOLHeader();  setParseState((next4Bytes == GROUP_VOP_START_CODE)                ? PARSING_GROUP_OF_VIDEO_OBJECT_PLANE		: PARSING_VIDEO_OBJECT_PLANE);  // Compute this frame's presentation time:  usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode);  // This header ends the 'configuration' information:  usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize());  usingSource()->completeNewConfig();  return curFrameSize();}unsigned MPEG4VideoStreamParser::parseGroupOfVideoObjectPlane() {#ifdef DEBUG  fprintf(stderr, "parsing GroupOfVideoObjectPlane\n");#endif  // Note that we've already read the GROUP_VOP_START_CODE  save4Bytes(GROUP_VOP_START_CODE);  // Next, extract the (18-bit) time code from the next 3 bytes:  u_int8_t next3Bytes[3];  getBytes(next3Bytes, 3);  saveByte(next3Bytes[0]);saveByte(next3Bytes[1]);saveByte(next3Bytes[2]);   unsigned time_code    = (next3Bytes[0]<<10)|(next3Bytes[1]<<2)|(next3Bytes[2]>>6);  unsigned time_code_hours    = (time_code&0x0003E000)>>13;  unsigned time_code_minutes  = (time_code&0x00001F80)>>7;#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)  Boolean marker_bit          = (time_code&0x00000040) != 0;#endif  unsigned time_code_seconds  = (time_code&0x0000003F);#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)  fprintf(stderr, "time_code: 0x%05x, hours %d, minutes %d, marker_bit %d, seconds %d\n", time_code, time_code_hours, time_code_minutes, marker_bit, time_code_seconds);#endif  // Now, copy all bytes that we see, up until we reach a VOP_START_CODE:  u_int32_t next4Bytes = get4Bytes();  while (next4Bytes != VOP_START_CODE) {    saveToNextCode(next4Bytes);  }    // Compute this frame's presentation time:  usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode);  // Record the time code:  usingSource()->setTimeCode(time_code_hours, time_code_minutes,                             time_code_seconds, 0, 0);    // Note: Because the GOV header can appear anywhere (not just at a 1s point), we    // don't pass "fTotalTicksSinceLastTimeCode" as the "picturesSinceLastGOP" parameter.  fSecondsSinceLastTimeCode = 0;  if (fixed_vop_rate) fTotalTicksSinceLastTimeCode = 0;  setParseState(PARSING_VIDEO_OBJECT_PLANE);  return curFrameSize();}unsigned MPEG4VideoStreamParser::parseVideoObjectPlane() {#ifdef DEBUG  fprintf(stderr, "#parsing VideoObjectPlane\n");#endif  // Note that we've already read the VOP_START_CODE  save4Bytes(VOP_START_CODE);  // Get the "vop_coding_type" from the next byte:  u_int8_t nextByte = get1Byte(); saveByte(nextByte);  u_int8_t vop_coding_type = nextByte>>6;  // Next, get the "modulo_time_base" by counting the '1' bits that follow.  // We look at the next 32-bits only.  This should be enough in most cases.  u_int32_t next4Bytes = get4Bytes();  u_int32_t timeInfo = (nextByte<<(32-6))|(next4Bytes>>6);  unsigned modulo_time_base = 0;  u_int32_t mask = 0x80000000;  while ((timeInfo&mask) != 0) {    ++modulo_time_base;    mask >>= 1;  }  mask >>= 1;  // Check the following marker bit:  if ((timeInfo&mask) == 0) {    usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectPlane(): marker bit not set!\n";  }  mask >>= 1;  // Then, get the "vop_time_increment".  // First, make sure we have enough bits left for this:  if ((mask>>(fNumVTIRBits-1)) == 0) {    usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectPlane(): 32-bits are not enough to get \"vop_time_increment\"!\n";  }  unsigned vop_time_increment = 0;  for (unsigned i = 0; i < fNumVTIRBits; ++i) {    vop_time_increment |= timeInfo&mask;    mask >>= 1;  }  while (mask != 0) {    vop_time_increment >>= 1;    mask >>= 1;  }#ifdef DEBUG  fprintf(stderr, "vop_coding_type: %d(%c), modulo_time_base: %d, vop_time_increment: %d\n", vop_coding_type, "IPBS"[vop_coding_type], modulo_time_base, vop_time_increment);#endif      // Now, copy all bytes that we see, up until we reach a code of some sort:  saveToNextCode(next4Bytes);    // Update our counters based on the frame timing information that we saw:  if (fixed_vop_time_increment > 0) {    // This is a 'fixed_vop_rate' stream.  Use 'fixed_vop_time_increment':    usingSource()->fPictureCount += fixed_vop_time_increment;    if (vop_time_increment > 0 || modulo_time_base > 0) {      fTotalTicksSinceLastTimeCode += fixed_vop_time_increment;      // Note: "fSecondsSinceLastTimeCode" and "fPrevNewTotalTicks" are not used.    }  } else {    // Use 'vop_time_increment':    unsigned newTotalTicks      = (fSecondsSinceLastTimeCode + modulo_time_base)*vop_time_increment_resolution      + vop_time_increment;    if (newTotalTicks == fPrevNewTotalTicks && fPrevNewTotalTicks > 0) {      // This is apparently a buggy MPEG-4 video stream, because      // "vop_time_increment" did not change.  Overcome this error,      // by pretending that it did change.#ifdef DEBUG      fprintf(stderr, "Buggy MPEG-4 video stream: \"vop_time_increment\" did not change!\n");#endif      // The following assumes that we don't have 'B' frames.  If we do, then TARFU!      usingSource()->fPictureCount += vop_time_increment;      fTotalTicksSinceLastTimeCode += vop_time_increment;      fSecondsSinceLastTimeCode += modulo_time_base;    } else {      if (newTotalTicks < fPrevNewTotalTicks && vop_coding_type != 2/*B*/	  && modulo_time_base == 0 && vop_time_increment == 0) {	// This is another kind of buggy MPEG-4 video stream, in which	// "vop_time_increment" wraps around, but without	// "modulo_time_base" changing.  Overcome this by pretending that	// "vop_time_increment" really did wrap around:#ifdef DEBUG	fprintf(stderr, "Buggy MPEG-4 video stream: \"vop_time_increment\" wrapped around, but without \"modulo_time_base\" changing!\n");#endif	++fSecondsSinceLastTimeCode;	newTotalTicks += vop_time_increment_resolution;      }      fPrevNewTotalTicks = newTotalTicks;      if (vop_coding_type != 2/*B*/) {	int pictureCountDelta = newTotalTicks - fTotalTicksSinceLastTimeCode;	if (pictureCountDelta <= 0) pictureCountDelta = fPrevPictureCountDelta;	    // ensures that the picture count is always increasing	usingSource()->fPictureCount += pictureCountDelta;	fPrevPictureCountDelta = pictureCountDelta;	fTotalTicksSinceLastTimeCode = newTotalTicks;	fSecondsSinceLastTimeCode += modulo_time_base;      }    }  }    // The next thing to parse depends on the code that we just saw,  // but we are assumed to have ended the current picture:   usingSource()->fPictureEndMarker = True; // HACK #####  switch (next4Bytes) {  case VISUAL_OBJECT_SEQUENCE_END_CODE: {    setParseState(PARSING_VISUAL_OBJECT_SEQUENCE_END_CODE);    break;  }  case VISUAL_OBJECT_SEQUENCE_START_CODE: {    setParseState(PARSING_VISUAL_OBJECT_SEQUENCE_SEEN_CODE);    break;  }  case GROUP_VOP_START_CODE: {    setParseState(PARSING_GROUP_OF_VIDEO_OBJECT_PLANE);    break;  }  case VOP_START_CODE: {    setParseState(PARSING_VIDEO_OBJECT_PLANE);    break;  }  default: {    usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectPlane(): Saw unexpected code "			   << (void*)next4Bytes << "\n";    setParseState(PARSING_VIDEO_OBJECT_PLANE); // the safest way to recover...    break;  }  }  // Compute this frame's presentation time:  usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode);  return curFrameSize();}unsigned MPEG4VideoStreamParser::parseVisualObjectSequenceEndCode() {#ifdef DEBUG  fprintf(stderr, "parsing VISUAL_OBJECT_SEQUENCE_END_CODE\n");#endif  // Note that we've already read the VISUAL_OBJECT_SEQUENCE_END_CODE  save4Bytes(VISUAL_OBJECT_SEQUENCE_END_CODE);  setParseState(PARSING_VISUAL_OBJECT_SEQUENCE);  // Treat this as if we had ended a picture:  usingSource()->fPictureEndMarker = True; // HACK #####  return curFrameSize();}

⌨️ 快捷键说明

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