Beispiel #1
0
bool MP4AV_RfcIsmaFragmenter(
	MP4FileHandle mp4File, 
	MP4TrackId mediaTrackId, 
	MP4TrackId hintTrackId,
	MP4SampleId sampleId, 
	u_int32_t sampleSize, 
	MP4Duration sampleDuration,
	u_int16_t maxPayloadSize)
{
  if (MP4AddRtpHint(mp4File, hintTrackId) == false ||
      MP4AddRtpPacket(mp4File, hintTrackId, false) == false) 
    return false;

  // Note: CELP is never fragmented
  // so we assume the two byte AAC-hbr payload header
  u_int8_t payloadHeader[4];
  payloadHeader[0] = 0;
  payloadHeader[1] = 16;
  payloadHeader[2] = sampleSize >> 5;
  payloadHeader[3] = (sampleSize & 0x1F) << 3;

  if (MP4AddRtpImmediateData(mp4File, hintTrackId,
			     (u_int8_t*)&payloadHeader, 
			     sizeof(payloadHeader)) == false) 
    return false;

  u_int16_t sampleOffset = 0;
  u_int16_t fragLength = maxPayloadSize - 4;

  do {
    if (MP4AddRtpSampleData(mp4File, hintTrackId,
			    sampleId, 
			    sampleOffset, 
			    fragLength) == false) return false;

    sampleOffset += fragLength;

    if (sampleSize - sampleOffset > maxPayloadSize) {
      fragLength = maxPayloadSize; 
      if (MP4AddRtpPacket(mp4File, hintTrackId, false) == false) return false;
    } else {
      fragLength = sampleSize - sampleOffset; 
      if (fragLength) {
	if (MP4AddRtpPacket(mp4File, hintTrackId, true) == false) return false;
      }
    }
  } while (sampleOffset < sampleSize);

  return MP4WriteRtpHint(mp4File, hintTrackId, sampleDuration);
}
Beispiel #2
0
extern "C" bool MP4AV_Rfc3016_HintAddSample (
    MP4FileHandle mp4File,
    MP4TrackId hintTrackId,
    MP4SampleId sampleId,
    uint8_t *pSampleBuffer,
    uint32_t sampleSize,
    MP4Duration duration,
    MP4Duration renderingOffset,
    bool isSyncSample,
    uint16_t maxPayloadSize)
{
    bool isBFrame =
        (MP4AV_Mpeg4GetVopType(pSampleBuffer, sampleSize) == VOP_TYPE_B);

    if (MP4AddRtpVideoHint(mp4File, hintTrackId, isBFrame, renderingOffset) == false)
        return false;

    if (sampleId == 1) {
        if (MP4AddRtpESConfigurationPacket(mp4File, hintTrackId) == false) return false;
    }

    u_int32_t offset = 0;
    u_int32_t remaining = sampleSize;

    // TBD should scan for resync markers (if enabled in ES config)
    // and packetize on those boundaries

    while (remaining) {
        bool isLastPacket = false;
        u_int32_t length;

        if (remaining <= maxPayloadSize) {
            length = remaining;
            isLastPacket = true;
        } else {
            length = maxPayloadSize;
        }

        if (MP4AddRtpPacket(mp4File, hintTrackId, isLastPacket) == false ||

                MP4AddRtpSampleData(mp4File, hintTrackId, sampleId,
                                    offset, length) == false) return false;

        offset += length;
        remaining -= length;
    }

    return MP4WriteRtpHint(mp4File, hintTrackId, duration, isSyncSample);
}
Beispiel #3
0
//#define DEBUG_G711 1
extern "C" bool G711Hinter (MP4FileHandle mp4file, 
			    MP4TrackId trackid,
			    uint16_t maxPayloadSize)
{
  uint32_t numSamples;
  uint8_t audioType;
  MP4SampleId sampleId;
  uint32_t sampleSize;
  MP4TrackId hintTrackId;
  uint8_t payload;
  uint32_t bytes_this_hint;
  uint32_t sampleOffset;

  numSamples = MP4GetTrackNumberOfSamples(mp4file, trackid);

  if (numSamples == 0) return false;

  audioType = MP4GetTrackEsdsObjectTypeId(mp4file, trackid);

  if (audioType != MP4_ALAW_AUDIO_TYPE &&
      audioType != MP4_ULAW_AUDIO_TYPE) return false;

  hintTrackId = MP4AddHintTrack(mp4file, trackid);

  if (hintTrackId == MP4_INVALID_TRACK_ID) {
    return false;
  }
  const char *type;

  if (audioType == MP4_ALAW_AUDIO_TYPE) {
    payload = 8;
    type = "PCMA";
  } else {
    payload = 0;
    type = "PCMU";
  }

  MP4SetHintTrackRtpPayload(mp4file, hintTrackId, type, &payload, 0,NULL,
			    false);

  MP4Duration sampleDuration;
  bool have_skip;
  sampleId = 1;
  sampleSize = MP4GetSampleSize(mp4file, trackid, sampleId);
  sampleDuration = MP4GetSampleDuration(mp4file, trackid, sampleId);
  have_skip = sampleDuration != sampleSize;
  sampleOffset = 0;
  bytes_this_hint = 0;

  if (maxPayloadSize > 160) maxPayloadSize = 160;

  while (1) {
    if (bytes_this_hint == 0) {
#ifdef DEBUG_G711
      printf("Adding hint/packet\n");
#endif
      MP4AddRtpHint(mp4file, hintTrackId);
      MP4AddRtpPacket(mp4file, hintTrackId, false); // marker bit 0
    }
    uint16_t bytes_left_this_packet;
    bytes_left_this_packet = maxPayloadSize - bytes_this_hint;
    if (sampleSize >= bytes_left_this_packet) {
      MP4AddRtpSampleData(mp4file, hintTrackId, 
			  sampleId, sampleOffset, bytes_left_this_packet);
      bytes_this_hint += bytes_left_this_packet;
      sampleSize -= bytes_left_this_packet;
      sampleOffset += bytes_left_this_packet;
#ifdef DEBUG_G711
      printf("Added sample with %u bytes\n", bytes_left_this_packet);
#endif
    } else {
      MP4AddRtpSampleData(mp4file, hintTrackId, 
			  sampleId, sampleOffset, sampleSize);
      bytes_this_hint += sampleSize;
#ifdef DEBUG_G711
      printf("Added sample with %u bytes\n", sampleSize);
#endif
      sampleSize = 0;
    }

    if (bytes_this_hint >= maxPayloadSize) {
      // Write the hint
      // duration is bytes written
      MP4WriteRtpHint(mp4file, hintTrackId, bytes_this_hint);
#ifdef DEBUG_G711
      printf("Finished packet - bytes %u\n", bytes_this_hint);
#endif
      bytes_this_hint = 0;
    }
    if (sampleSize == 0) {
      // next sample
      if (have_skip && bytes_this_hint != 0) {
#ifdef DEBUG_G711
	printf("duration - ending packet - bytes %u\n", bytes_this_hint);
#endif
	MP4WriteRtpHint(mp4file, hintTrackId, bytes_this_hint);
	bytes_this_hint = 0;
      }
      sampleId++;
      if (sampleId > numSamples) {
	// finish it and exit
	if (bytes_this_hint != 0) {
	  MP4WriteRtpHint(mp4file, hintTrackId, bytes_this_hint);
	}
	return true;
      }
      sampleSize = MP4GetSampleSize(mp4file, trackid, sampleId);
      sampleDuration = MP4GetSampleDuration(mp4file, trackid, sampleId);
      have_skip = sampleDuration != sampleSize;
#ifdef DEBUG_G711
      printf("Next sample %u - size %u %u\n", sampleId, sampleSize,
	     have_skip);
#endif
      sampleOffset = 0;
    }
  }
	
  return true; // will never reach here
}
Beispiel #4
0
extern "C" bool MP4AV_Rfc2429Hinter (MP4FileHandle file,
				     MP4TrackId mediaTrackId,
				     uint16_t maxPayloadSize)
{
  uint32_t numSamples, maxSampleSize;
  MP4TrackId hid;
  MP4Duration duration;

  numSamples = MP4GetTrackNumberOfSamples(file, mediaTrackId);
  if (numSamples == 0) {
    return false;
  }
  maxSampleSize = MP4GetTrackMaxSampleSize(file, mediaTrackId);
  u_int8_t* pSampleBuffer = (u_int8_t*)malloc(maxSampleSize);
  if (pSampleBuffer == NULL) {
    return false;
  }

  hid = MP4AddHintTrack(file, mediaTrackId);
  if (hid == MP4_INVALID_TRACK_ID) {
    return false;
  }

  uint8_t payloadNumber = MP4_SET_DYNAMIC_PAYLOAD;
  MP4SetHintTrackRtpPayload(file,
                            hid,
                            "H263-2000",
                            &payloadNumber,
                            0,
                            NULL,
                            true,
                            false);

  // strictly speaking, this is not required for H.263 - it's a quicktime
  // thing.
  u_int16_t videoWidth = MP4GetTrackVideoWidth(file, mediaTrackId);
  u_int16_t videoHeight = MP4GetTrackVideoHeight(file, mediaTrackId);
  
  char sdpString[80];
  sprintf(sdpString, "a=cliprect:0,0,%d,%d\015\012", videoHeight, videoWidth);
  
  MP4AppendHintTrackSdp(file, 
 			hid,
 			sdpString);

  for (uint32_t sid = 1; sid <= numSamples; sid++) {

    duration = MP4GetSampleDuration(file, mediaTrackId, sid);

    MP4AddRtpVideoHint(file, hid, false, 0);

    u_int32_t sampleSize = maxSampleSize;
    MP4Timestamp startTime;
    MP4Duration duration;
    MP4Duration renderingOffset;
    bool isSyncSample;

    bool rc = MP4ReadSample(file, mediaTrackId, sid,
                            &pSampleBuffer, &sampleSize,
                            &startTime, &duration,
                            &renderingOffset, &isSyncSample);

    if (!rc) {
      MP4DeleteTrack(file, hid);
      free(pSampleBuffer);
      return false;
    }

    // need to skip the first 2 bytes of the packet - it is the
    //start code
    uint16_t payload_head = htons(0x400);
    uint32_t offset = sizeof(payload_head);
    uint32_t remaining = sampleSize - sizeof(payload_head);
    while (remaining) {
      bool last_pak = false;
      uint32_t len;

      if (remaining + 2 <= maxPayloadSize) {
        len = remaining;
        last_pak = true;
      } else {
        len = maxPayloadSize - 2;
      }
      MP4AddRtpPacket(file, hid, last_pak);

      MP4AddRtpImmediateData(file, hid,
                            (u_int8_t*)&payload_head, sizeof(payload_head));
      payload_head = 0;
      MP4AddRtpSampleData(file, hid, sid,
                          offset, len);
      offset += len;
      remaining -= len;
    }
    MP4WriteRtpHint(file, hid, duration, true);
  }

  free(pSampleBuffer);

  return true;
}
Beispiel #5
0
extern "C" void MP4AV_AVSM_HintAddSample (MP4FileHandle mp4File,
					  MP4TrackId hintTrackId,
					  MP4SampleId sampleId,
					  uint8_t *pSampleBuffer,
					  uint32_t sampleSize,				//sampleSize:整个sample多少个byte
					  uint32_t sizeLength,
					  MP4Duration duration,
					  MP4Duration renderingOffset,
					  bool isSyncSample,
					  uint16_t maxPayloadSize)
{
  uint8_t nal_type = avsm_get_sample_nal_type(pSampleBuffer, 
					      sampleSize, 
					      sizeLength);
  bool pic_is_idr = false;
  if (nal_type == AVSM_NAL_TYPE_IDR_PIC_HEADER) 
  {
	  pic_is_idr=true;
  }

  // for now, we don't know if we can drop frames, so don't indiate
  // that any are "b" frames
  bool isBFrame = false;
  uint32_t nal_size;									//nal_size:一个nalu多少个byte,不包括前面打包的4byte,包括nalu头
  uint32_t offset = 0;
  uint32_t remaining = sampleSize;	
/*#ifdef DEBUG_H264_HINT			
  printf("hint for sample %d %u\n", sampleId, remaining);
#endif*/
  MP4AddRtpVideoHint(mp4File, hintTrackId, isBFrame, renderingOffset);

  if (sampleSize - sizeLength < maxPayloadSize) {				//sample小于MTU	sizelength相当于是头信息不包括在sample的净荷内				
    uint32_t first_nal = avsm_get_nal_size(pSampleBuffer, sizeLength);
    if (first_nal + sizeLength == sampleSize) {					//一个sample只有一个nalu,且小于MTU时的情况
      // we have a single nal, less than the maxPayloadSize,	//只要打一个rtp包就可以了
      // so, we have Single Nal unit mode
      MP4AddRtpPacket(mp4File, hintTrackId, true);
      MP4AddRtpSampleData(mp4File, hintTrackId, sampleId,
			  sizeLength, sampleSize - sizeLength);
      MP4WriteRtpHint(mp4File, hintTrackId, duration, 
		      pic_is_idr);//nal_type改变规则
      return;
    }
  }

  // TBD should scan for resync markers (if enabled in ES config)
  // and packetize on those boundaries
  while (remaining) {				//sample数据大于MTU时,只要这个sample还有数据就执行********sample层**循环*******************

    nal_size = avsm_get_nal_size(pSampleBuffer + offset,
					  sizeLength);								//sizelength=4
    //******* skip the sizeLength								
/*#ifdef DEBUG_H264_HINT//不执行
    printf("offset %u nal size %u remain %u\n", offset, nal_size, remaining);
#endif*/

    offset += sizeLength;
    remaining -= sizeLength;

	if (nal_size > maxPayloadSize) {				//如果nalu_size大于最大允许值MTU 需要分割 FU
#ifdef DEBUG_H264_HINT								//FU头8bit含义见说明
      printf("fragmentation units\n");
#endif
      uint8_t head = pSampleBuffer[offset];//************************************************************************
      offset++;
      nal_size--;
      remaining--;
	  
      uint8_t fu_header[2];
	 // uint8_t *final_fu_header;
      fu_header[0] = (head&0xe0)|0x1c;			//FU指示
      fu_header[1] = head;						//FU头
	  fu_header[1] |= 0x80;
	  fu_header[1] &= 0x9f;				//100+type5bit
	  

	while (nal_size > 0) {			//******************只要nalu还有值************************nalu层**循环*******************
	
	
	uint32_t write_size;
	if (nal_size + 2 <= maxPayloadSize) {//如果nalu净荷加nalu头和FU头小于等于MTU则结束分割单元
	  fu_header[1] |= 0x40;//分割单元结束
	  write_size = nal_size;
	} else {
	  write_size = maxPayloadSize - 2;//write_size就是这个分割单元包括的payload=MTU-2
	}
#ifdef DEBUG_H264_HINT
	printf("frag off %u write %u left in nal %u remain %u\n",
	       offset, write_size, nal_size, remaining);
#endif
	remaining -= write_size;//remaining为分完一个MTU后这个sample剩余的数据

	MP4AddRtpPacket(mp4File, hintTrackId, remaining == 0);
	MP4AddRtpImmediateData(mp4File, hintTrackId, 
			      fu_header, 2);
	fu_header[1] &= 0x7f;//表示结束第一个分割单元

	MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, 
			    offset, write_size);
	offset += write_size;
	nal_size -= write_size;//nal_size为这个nalu分割后剩余的数据,如果还有数据就在此循环,组成新的分割单元
      }
    }								//************FU****end********
  
	else {												//如果nalu_size 小于 最大允许值MTU,则要考虑是否打复合包stap
      // we have a smaller than MTU nal.  check the next sample			//这句话什么意思,为什么是next sample,应该是nalu吧
      // see if the next one fits;				
      uint32_t next_size_offset;
      bool have_stap = false;
      next_size_offset = offset + nal_size;
      if (next_size_offset < sampleSize) {//if (next_size_offset < remaining) {//是否有下一个nalu?有,则执行下面 remaining改成samplesize
	// we have a remaining NAL
	uint32_t next_nal_size = 
	  avsm_get_nal_size(pSampleBuffer + next_size_offset, sizeLength);
	if (next_nal_size + nal_size + 4 + 1 <= maxPayloadSize) {					//判断下一个两个nalu大小加起来是否小于MTU
	  have_stap = true;															//小于MTU的话,我们就用STAP复合包
	}																		//4 两个NALU尺寸 1 一个STAP-A净载头 (NALU尺寸为1byte)
      } 
      if (have_stap == false) {									//如果两个nalu大于MTU则不用STAP,直接把这个nalu打成一个rtp包,下一个再重新判断
	MP4AddRtpPacket(mp4File, hintTrackId, next_size_offset >= remaining);
	MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, 
			    offset, nal_size);
	offset += nal_size;
	remaining -= nal_size;
      } 
	  
	  else {													//****************如果两个NALU小于MTU则使用STAP-A复合包实现******
	uint32_t bytes_in_stap = 1 + 2 + nal_size;					//1byte STAP-A净载头;2byte是STAP的nalu尺寸:表明随后nalu(包括nalu头)大小

	
	uint8_t max_nri = pSampleBuffer[offset] & 0x60;	//0 11 00000	//**重要问题:一个sample包含几个nalu**
	while (next_size_offset <= sampleSize && bytes_in_stap <= maxPayloadSize)//while (next_size_offset < sampleSize && bytes_in_stap <= maxPayloadSize) //remaining改成samplesize//while (next_size_offset < remaining && bytes_in_stap < maxPayloadSize) 
	{													
	  uint8_t nri;										//在一个stap内比较出nalu最大的NRI优先级,在净载头中NRI单元就用最大优先级
	  nri = pSampleBuffer[next_size_offset + sizeLength] & 0x60;		//0 11 00000
	  if (nri > max_nri) max_nri = nri;
	  
	  uint32_t next_nal_size = 
	    avsm_get_nal_size(pSampleBuffer + next_size_offset, sizeLength);
	  bytes_in_stap += 2 + next_nal_size;
	  next_size_offset += sizeLength + next_nal_size;
	}

	//下面验证是否是最后一个nalu
	bool last;
	if (next_size_offset > sampleSize)// && bytes_in_stap <= maxPayloadSizey)//if (next_size_offset <= remaining && bytes_in_stap <= maxPayloadSize)		
	  // stap is last frame						//已经到了这个sample最后一个nalu,M标志位置1,表示sample结束
	{
		last = true;
	} else last = false;						
	MP4AddRtpPacket(mp4File, hintTrackId, last);//last=true时z说明这个stap是这个sample最后一个stap,把M标志位置1
	uint8_t data[3];
	data[0] = max_nri | 24;						//stap-A 净载头
	data[1] = nal_size >> 8;
	data[2] = nal_size & 0xff;					//NALU尺寸2 byte
	MP4AddRtpImmediateData(mp4File, hintTrackId, 
			       data, 3);
	MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, 
			    offset, nal_size);
	offset += nal_size;
	remaining -= nal_size;
	bytes_in_stap = 1 + 2 + nal_size;							//1byte STAP-A净载头;2byte是STAP的nalu尺寸:表明随后nalu(包括nalu头)大小
	nal_size = avsm_get_nal_size(pSampleBuffer + offset, sizeLength);
	while (bytes_in_stap + nal_size + 2 <= maxPayloadSize &&remaining) {			//***当两个NALU以后还小于MTU则下面的nalu再打入stap**循环*
	  offset += sizeLength;
	  remaining -= sizeLength;
	  data[0] = nal_size >> 8;
	  data[1] = nal_size & 0xff;
	  MP4AddRtpImmediateData(mp4File, hintTrackId, data, 2);
	  MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, offset, nal_size);
	  offset += nal_size;
	  remaining -= nal_size;
	  bytes_in_stap += nal_size + 2;							//再次将nalu打入stap时就不用再加1byte净载头了,只需要加2byte nalu尺寸
	  if (remaining) {
	    nal_size = avsm_get_nal_size(pSampleBuffer + offset, sizeLength);
	  }
	} // end while stap
     } // end have stap	  
	} // end check size
   }
    MP4WriteRtpHint(mp4File, hintTrackId, duration,				//整个sample读完后写??!
	   pic_is_idr);
 
}
Beispiel #6
0
bool MP4AV_RfcIsmaConcatenator(
	MP4FileHandle mp4File, 
	MP4TrackId mediaTrackId, 
	MP4TrackId hintTrackId,
	u_int8_t samplesThisHint, 
	MP4SampleId* pSampleIds, 
	MP4Duration hintDuration,
	u_int16_t maxPayloadSize)
{
  // handle degenerate case
  if (samplesThisHint == 0) {
    return true;
  }

  u_int8_t auPayloadHdrSize;

  // LATER would be more efficient if this were a parameter
  u_int8_t mpeg4AudioType =
    MP4GetTrackAudioMpeg4Type(mp4File, mediaTrackId);

  if (mpeg4AudioType == MP4_MPEG4_CELP_AUDIO_TYPE) {
    auPayloadHdrSize = 1;
  } else {
    auPayloadHdrSize = 2;
  }

  // construct the new hint
  if (MP4AddRtpHint(mp4File, hintTrackId) == false ||
      MP4AddRtpPacket(mp4File, hintTrackId, true) == false) return false;

  u_int8_t payloadHeader[2];

  u_int16_t numHdrBits = samplesThisHint * auPayloadHdrSize * 8;
  payloadHeader[0] = numHdrBits >> 8;
  payloadHeader[1] = numHdrBits & 0xFF;

  if (MP4AddRtpImmediateData(mp4File, hintTrackId,
			     (u_int8_t*)&payloadHeader, 
			     sizeof(payloadHeader)) == false) return false;

  u_int8_t i;

  // first the headers
  for (i = 0; i < samplesThisHint; i++) {
    MP4SampleId sampleId = pSampleIds[i];

    u_int32_t sampleSize = 
      MP4GetSampleSize(mp4File, mediaTrackId, sampleId);

    if (auPayloadHdrSize == 1) {
      // AU payload header is 6 bits of size
      // follow by 2 bits of the difference between sampleId's - 1
      payloadHeader[0] = sampleSize << 2;

    } else { // auPayloadHdrSize == 2
      // AU payload header is 13 bits of size
      // follow by 3 bits of the difference between sampleId's - 1
      payloadHeader[0] = sampleSize >> 5;
      payloadHeader[1] = (sampleSize & 0x1F) << 3;
    }

    if (i > 0) {
      payloadHeader[auPayloadHdrSize - 1] 
	|= ((sampleId - pSampleIds[i-1]) - 1); 
    }
#if 0
    printf("sample %u size %u %02x %02x prev sample %d\n", 
	   sampleId, sampleSize, payloadHeader[0],
	   payloadHeader[1], pSampleIds[i-1]);
#endif

    if (MP4AddRtpImmediateData(mp4File, hintTrackId,
			       (u_int8_t*)&payloadHeader, 
			       auPayloadHdrSize) == false) 
      return false;
  }

  // then the samples
  for (i = 0; i < samplesThisHint; i++) {
    MP4SampleId sampleId = pSampleIds[i];

    u_int32_t sampleSize = 
      MP4GetSampleSize(mp4File, mediaTrackId, sampleId);

    if (MP4AddRtpSampleData(mp4File, hintTrackId, 
			    sampleId, 0, sampleSize) == false) return false;
  }

  // write the hint
  return MP4WriteRtpHint(mp4File, hintTrackId, hintDuration);
}
Beispiel #7
0
extern "C" void MP4AV_H264_HintAddSample (MP4FileHandle mp4File,
					  MP4TrackId hintTrackId,
					  MP4SampleId sampleId,
					  uint8_t *pSampleBuffer,
					  uint32_t sampleSize,
					  uint32_t sizeLength,
					  MP4Duration duration,
					  MP4Duration renderingOffset,
					  bool isSyncSample,
					  uint16_t maxPayloadSize)
{
  uint8_t nal_type = h264_get_sample_nal_type(pSampleBuffer, 
					      sampleSize, 
					      sizeLength);
  // for now, we don't know if we can drop frames, so don't indiate
  // that any are "b" frames
  bool isBFrame = false;
  uint32_t nal_size;
  uint32_t offset = 0;
  uint32_t remaining = sampleSize;
#ifdef DEBUG_H264_HINT
  printf("hint for sample %d %u\n", sampleId, remaining);
#endif
  MP4AddRtpVideoHint(mp4File, hintTrackId, isBFrame, renderingOffset);

  if (sampleSize - sizeLength < maxPayloadSize) {
    uint32_t first_nal = h264_get_nal_size(pSampleBuffer, sizeLength);
    if (first_nal + sizeLength == sampleSize) {
      // we have a single nal, less than the maxPayloadSize, 
      // so, we have Single Nal unit mode
      MP4AddRtpPacket(mp4File, hintTrackId, true);
      MP4AddRtpSampleData(mp4File, hintTrackId, sampleId,
			  sizeLength, sampleSize - sizeLength);
      MP4WriteRtpHint(mp4File, hintTrackId, duration, 
		      nal_type == H264_NAL_TYPE_IDR_SLICE);
      return;
    }
  }

  // TBD should scan for resync markers (if enabled in ES config)
  // and packetize on those boundaries
  while (remaining) {
    nal_size = h264_get_nal_size(pSampleBuffer + offset,
					  sizeLength);
    // skip the sizeLength
#ifdef DEBUG_H264_HINT
    printf("offset %u nal size %u remain %u\n", offset, nal_size, remaining);
#endif

    offset += sizeLength;
    remaining -= sizeLength;
    if (nal_size > maxPayloadSize) {
      /*
       * We have fragmentation of a NAL here
       */
#ifdef DEBUG_H264_HINT
      printf("fragmentation units\n");
#endif
      uint8_t head = pSampleBuffer[offset];
      offset++;
      nal_size--;
      remaining--;
      uint8_t fu_header[2];
      fu_header[0] = (head & 0xe0) | 28; 
      fu_header[1] = 0x80;
      head &= 0x1f;
      while (nal_size > 0) {
	fu_header[1] |= head;
	uint32_t write_size;
	if (nal_size + 2 <= maxPayloadSize) {
	  fu_header[1] |= 0x40;
	  write_size = nal_size;
	} else {
	  write_size = maxPayloadSize - 2;
	}
#ifdef DEBUG_H264_HINT
	printf("frag off %u write %u left in nal %u remain %u\n",
	       offset, write_size, nal_size, remaining);
#endif
	remaining -= write_size;

	MP4AddRtpPacket(mp4File, hintTrackId, remaining == 0);
	MP4AddRtpImmediateData(mp4File, hintTrackId, 
			       fu_header, 2);
	fu_header[1] = 0;

	MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, 
			    offset, write_size);
	offset += write_size;
	nal_size -= write_size;
      }
    } else {
      // we have a smaller than MTU nal.  check the next sample
      // see if the next one fits;
      uint32_t next_size_offset;
      bool have_stap = false;
      next_size_offset = offset + nal_size;
      if (next_size_offset < remaining) {
	// we have a remaining NAL
	uint32_t next_nal_size = 
	  h264_get_nal_size(pSampleBuffer + next_size_offset, sizeLength);
#ifdef DEBUG_H264_HINT
	printf("next nal size %u\n", next_nal_size);
#endif
	if (next_nal_size + nal_size + 4 + 1 <= maxPayloadSize) {
	  have_stap = true;
	} 
      } 
      if (have_stap == false) {
	// we have to fit this nal into a packet - the next one is too big
#ifdef DEBUG_H264_HINT
	printf("have single NAL packet \n");
#endif
	MP4AddRtpPacket(mp4File, hintTrackId, next_size_offset >= remaining);
	MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, 
			    offset, nal_size);
	offset += nal_size;
	remaining -= nal_size;
      } else {
	// we can fit multiple NALs into this packet
	uint32_t bytes_in_stap = 1 + 2 + nal_size;
	uint8_t max_nri = pSampleBuffer[offset] & 0x70;
#ifdef DEBUG_H264_HINT
	printf("Start processing stap\n");
#endif
	while (next_size_offset < remaining && bytes_in_stap < maxPayloadSize) {
	  uint8_t nri;
	  nri = pSampleBuffer[next_size_offset + sizeLength] & 0x70;
	  if (nri > max_nri) max_nri = nri;
	  
	  uint32_t next_nal_size = 
	    h264_get_nal_size(pSampleBuffer + next_size_offset, sizeLength);
	  bytes_in_stap += 2 + next_nal_size;
	  next_size_offset += sizeLength + next_nal_size;
#ifdef DEBUG_H264_HINT
	  printf("next nal %u bytes in stap %u next offset %u\n",
		 next_nal_size, bytes_in_stap, next_size_offset);
#endif
	}
	bool last;
#ifdef DEBUG_H264_HINT
	printf("done - next_size offset %u remain %u bytes %u\n",
	       next_size_offset, remaining, bytes_in_stap);
#endif
	if (next_size_offset >= (offset +  remaining) && 
	    bytes_in_stap <= maxPayloadSize) {
	  // stap is last frame
	  last = true;
	} else last = false;
	MP4AddRtpPacket(mp4File, hintTrackId, last);
	uint8_t data[3];
	data[0] = max_nri | 24;
	data[1] = nal_size >> 8;
	data[2] = nal_size & 0xff;
	MP4AddRtpImmediateData(mp4File, hintTrackId, 
			       data, 3);
	MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, 
			    offset, nal_size);
	offset += nal_size;
	remaining -= nal_size;
	bytes_in_stap = 1 + 2 + nal_size;
	nal_size = h264_get_nal_size(pSampleBuffer + offset, sizeLength);
	while (bytes_in_stap + nal_size <= maxPayloadSize &&
	       remaining) {
	  offset += sizeLength;
	  remaining -= sizeLength;
	  data[0] = nal_size >> 8;
	  data[1] = nal_size & 0xff;
	  MP4AddRtpImmediateData(mp4File, hintTrackId, data, 2);
	  MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, offset, nal_size);
	  offset += nal_size;
	  remaining -= nal_size;
	  bytes_in_stap += nal_size + 2;
	  if (remaining) {
	    nal_size = h264_get_nal_size(pSampleBuffer + offset, sizeLength);
	  }
	} // end while stap
      } // end have stap
    } // end check size
  }

  MP4WriteRtpHint(mp4File, hintTrackId, duration, 
		  nal_type == H264_NAL_TYPE_IDR_SLICE);
}
Beispiel #8
0
extern "C" bool MP4AV_Rfc3016LatmHinter (MP4FileHandle mp4File,
        MP4TrackId mediaTrackId,
        u_int16_t maxPayloadSize)
{
    u_int32_t numSamples = MP4GetTrackNumberOfSamples(mp4File, mediaTrackId);
    u_int32_t maxSampleSize = MP4GetTrackMaxSampleSize(mp4File, mediaTrackId);
    MP4Duration sampleDuration =
        MP4AV_GetAudioSampleDuration(mp4File, mediaTrackId);

    if (sampleDuration == MP4_INVALID_DURATION) {
        return false;
    }

    if (numSamples == 0 || maxSampleSize == 0) {
        return false;
    }


    /* get the mpeg4 video configuration */
    u_int8_t* pAudioSpecificConfig;
    u_int32_t AudioSpecificConfigSize;

    if (MP4GetTrackESConfiguration(mp4File, mediaTrackId,
                                   &pAudioSpecificConfig,
                                   &AudioSpecificConfigSize) == false)
        return false;

    if (pAudioSpecificConfig == NULL ||
            AudioSpecificConfigSize == 0) return false;

    uint8_t channels = MP4AV_AacConfigGetChannels(pAudioSpecificConfig);
    uint32_t freq = MP4AV_AacConfigGetSamplingRate(pAudioSpecificConfig);
    uint8_t type = MP4AV_AacConfigGetAudioObjectType(pAudioSpecificConfig);

    uint8_t *pConfig;
    uint32_t configSize;

    MP4AV_LatmGetConfiguration(&pConfig, &configSize,
                               pAudioSpecificConfig, AudioSpecificConfigSize);
    free(pAudioSpecificConfig);

    if (pConfig == NULL || configSize == 0) {
        CHECK_AND_FREE(pConfig);
        return false;
    }

    MP4TrackId hintTrackId =
        MP4AddHintTrack(mp4File, mediaTrackId);

    if (hintTrackId == MP4_INVALID_TRACK_ID) {
        free(pConfig);
        return false;
    }
    u_int8_t payloadNumber = MP4_SET_DYNAMIC_PAYLOAD;

    char buffer[10];
    if (channels != 1) {
        snprintf(buffer, sizeof(buffer), "%u", channels);
    }

    /* convert it into ASCII form */
    char* sConfig = MP4BinaryToBase16(pConfig, configSize);
    free(pConfig);
    if (sConfig == NULL ||
            MP4SetHintTrackRtpPayload(mp4File, hintTrackId,
                                      "MP4A-LATM", &payloadNumber, 0,
                                      channels != 1 ? buffer : NULL) == false) {
        MP4DeleteTrack(mp4File, hintTrackId);
        return false;
    }

    uint32_t profile_level;
    // from gpac code
    switch (type) {
    case 2:
        if (channels <= 2) profile_level = freq <= 24000 ? 0x28 : 0x29;
        else profile_level = freq <= 48000 ? 0x2a : 0x2b;
        break;
    case 5:
        if (channels <= 2) profile_level = freq < 24000 ? 0x2c : 0x2d;
        else profile_level = freq <= 48000 ? 0x2e : 0x2f;
        break;
    default:
        if (channels <= 2) profile_level = freq < 24000 ? 0x0e : 0x0f;
        else profile_level = 0x10;
        break;
    }

    /* create the appropriate SDP attribute */
    char* sdpBuf = (char*)malloc(strlen(sConfig) + 128);

    if (sdpBuf == NULL) {
        free(sConfig);
        MP4DeleteTrack(mp4File, hintTrackId);
        return false;
    }
    snprintf(sdpBuf,
             strlen(sConfig) + 128,
             "a=fmtp:%u profile-level-id=%u; cpresent=0; config=%s;\015\012",
             payloadNumber,
             profile_level,
             sConfig);

    /* add this to the track's sdp */
    bool val = MP4AppendHintTrackSdp(mp4File, hintTrackId, sdpBuf);

    free(sConfig);
    free(sdpBuf);
    if (val == false) {
        MP4DeleteTrack(mp4File, hintTrackId);
        return false;
    }

    for (MP4SampleId sampleId = 1; sampleId <= numSamples; sampleId++) {
        uint8_t buffer[32];
        uint32_t offset = 0;
        uint32_t sampleSize =
            MP4GetSampleSize(mp4File, mediaTrackId, sampleId);
        uint32_t size_left = sampleSize;

        while (size_left > 0) {
            if (size_left > 0xff) {
                size_left -= 0xff;
                buffer[offset] = 0xff;
            } else {
                buffer[offset] = size_left;
                size_left = 0;
            }
            offset++;
        }
        if (MP4AddRtpHint(mp4File, hintTrackId) == false ||
                MP4AddRtpPacket(mp4File, hintTrackId, true) == false ||
                MP4AddRtpImmediateData(mp4File, hintTrackId,
                                       buffer, offset) == false ||
                MP4AddRtpSampleData(mp4File, hintTrackId,
                                    sampleId, 0, sampleSize) == false ||
                MP4WriteRtpHint(mp4File, hintTrackId, sampleDuration) == false) {
            MP4DeleteTrack(mp4File, hintTrackId);
            return false;
        }
    }
    return true;

}