bool CMp4H264VideoByteStream::start_next_frame (uint8_t **buffer, 
						uint32_t *buflen, 
						frame_timestamp_t *ts,
						void **ud)
{
  bool ret;
  uint32_t len = 1, read_offset = 0;
  uint32_t nal_len;
  uint32_t write_offset = 0;
  ret = CMp4VideoByteStream::start_next_frame(buffer, 
					      buflen, 
					      ts, 
					      ud);
  if (*buffer != NULL && *buflen != 0) {
    if (m_buflen_size == 0) {
      m_parent->lock_file_mutex();
      MP4GetTrackH264LengthSize(m_parent->get_file(), m_track, &m_buflen_size);
      m_parent->unlock_file_mutex();
    }
#ifdef DEBUG_H264_NALS
    mp4f_message(LOG_DEBUG, "new frame - len %u", *buflen);
#endif
    do {
      nal_len = read_nal_size(*buffer + read_offset);
#ifdef DEBUG_H264_NALS
      mp4f_message(LOG_DEBUG, "nal offset %u size %u", read_offset, 
		   nal_len);
#endif
      len += nal_len + 3;
      read_offset += nal_len + m_buflen_size;
    } while (read_offset < *buflen);
    if (len > m_translate_buffer_size) {
      m_translate_buffer = (uint8_t *)realloc(m_translate_buffer, len);
      m_translate_buffer_size = len;
#ifdef DEBUG_H264_NALS
      mp4f_message(LOG_DEBUG, "buflen alloced as %u", len);
#endif
    }
    read_offset = 0;
    do {
      nal_len = read_nal_size(*buffer + read_offset);
#ifdef DEBUG_H264_NALS
      mp4f_message(LOG_DEBUG, "write offset %u, read offset %u len %u",
		   write_offset, read_offset, nal_len);
#endif
      m_translate_buffer[write_offset] = 0;
      m_translate_buffer[write_offset + 1] = 0;
      if (write_offset == 0) {
	// make sure that the first nal has a extra 0 (0 0 0 1 header)
	m_translate_buffer[2] = 0;
	write_offset = 1;
      }
      m_translate_buffer[write_offset + 2] = 1;
      memcpy(m_translate_buffer + write_offset + 3, 
	     *buffer + read_offset + m_buflen_size,
	     nal_len);
      write_offset += nal_len + 3;
      read_offset += nal_len + m_buflen_size;
    } while (read_offset < *buflen);
    *buffer = m_translate_buffer;
    *buflen = write_offset;
  }
  return ret;
}
Beispiel #2
0
extern "C" bool MP4AV_H264Hinter(
				 MP4FileHandle mp4File, 
				 MP4TrackId mediaTrackId, 
				 u_int16_t maxPayloadSize)
{
  u_int32_t numSamples = MP4GetTrackNumberOfSamples(mp4File, mediaTrackId);
  u_int32_t maxSampleSize = MP4GetTrackMaxSampleSize(mp4File, mediaTrackId);
	
  uint32_t sizeLength;

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

  if (MP4GetTrackH264LengthSize(mp4File, mediaTrackId, &sizeLength) == false) {
    return false;
  }

  MP4TrackId hintTrackId = 
    MP4AV_H264_HintTrackCreate(mp4File, mediaTrackId);

  if (hintTrackId == MP4_INVALID_TRACK_ID) {
    return false;
  }

  u_int8_t* pSampleBuffer = (u_int8_t*)malloc(maxSampleSize);
  if (pSampleBuffer == NULL) {
    MP4DeleteTrack(mp4File, hintTrackId);
    return false;
  }
  for (MP4SampleId sampleId = 1; sampleId <= numSamples; sampleId++) {
    u_int32_t sampleSize = maxSampleSize;
    MP4Timestamp startTime;
    MP4Duration duration;
    MP4Duration renderingOffset;
    bool isSyncSample;

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

    if (!rc) {
      MP4DeleteTrack(mp4File, hintTrackId);
      CHECK_AND_FREE(pSampleBuffer);
      return false;
    }

    MP4AV_H264_HintAddSample(mp4File,
			     hintTrackId,
			     sampleId,
			     pSampleBuffer,
			     sampleSize,
			     sizeLength,
			     duration,
			     renderingOffset,
			     isSyncSample,
			     maxPayloadSize);
  }
  CHECK_AND_FREE(pSampleBuffer);

  return true;
}
static void DumpTrack (MP4FileHandle mp4file, MP4TrackId tid, 
		       bool dump_off, bool dump_rend)
{
  uint32_t numSamples;
  MP4SampleId sid;
  uint8_t *buffer;
  uint32_t max_frame_size;
  uint32_t timescale;
  uint64_t msectime;
  const char *media_data_name;
  uint32_t len_size = 0;
  uint8_t video_type = 0;
  numSamples = MP4GetTrackNumberOfSamples(mp4file, tid);
  max_frame_size = MP4GetTrackMaxSampleSize(mp4file, tid) + 4;
  media_data_name = MP4GetTrackMediaDataName(mp4file, tid);
  if (strcasecmp(media_data_name, "avc1") == 0) {
    MP4GetTrackH264LengthSize(mp4file, tid, &len_size);
  } else if (strcasecmp(media_data_name, "mp4v") == 0) {
    video_type = MP4GetTrackEsdsObjectTypeId(mp4file, tid);
  }
  buffer = (uint8_t *)malloc(max_frame_size);
  if (buffer == NULL) {
    printf("couldn't get buffer\n");
    return;
  }

  timescale = MP4GetTrackTimeScale(mp4file, tid);
  printf("mp4file %s, track %d, samples %d, timescale %d\n", 
	 Mp4FileName, tid, numSamples, timescale);

  for (sid = 1; sid <= numSamples; sid++) {
    MP4Timestamp sampleTime;
    MP4Duration sampleDuration, sampleRenderingOffset;
    bool isSyncSample = FALSE;
    bool ret;
    u_int8_t *temp;
    uint32_t this_frame_size = max_frame_size;
    temp = buffer;
    ret = MP4ReadSample(mp4file, 
			tid,
			sid,
			&temp,
			&this_frame_size,
			&sampleTime,
			&sampleDuration,
			&sampleRenderingOffset,
			&isSyncSample);

    msectime = sampleTime;
    msectime *= TO_U64(1000);
    msectime /= timescale;

    printf("sampleId %6d, size %5u time "U64"("U64")",
	  sid,  MP4GetSampleSize(mp4file, tid, sid), 
	   sampleTime, msectime);
    if (dump_rend) printf(" %6"U64F, sampleRenderingOffset);
    if (strcasecmp(media_data_name, "mp4v") == 0) {
      if (MP4_IS_MPEG4_VIDEO_TYPE(video_type))
	ParseMpeg4(temp, this_frame_size, dump_off);
    } else if (strcasecmp(media_data_name, "avc1") == 0) {
      ParseH264(temp, this_frame_size, len_size, dump_off);
    }
    printf("\n");
  }
}
Beispiel #4
0
bool CMp4EncH264VideoByteStream::start_next_frame (uint8_t **buffer, 
						uint32_t *buflen, 
						frame_timestamp_t *ts,
						void **ud)
{
  bool ret;
  uint32_t len = 1, read_offset = 0;
  uint32_t nal_len;
  uint32_t write_offset = 0;

  u_int8_t *temp_buffer = NULL;
  u_int32_t temp_this_frame_size = 0;
  ismacryp_rc_t ismacryprc;

  ret = CMp4VideoByteStream::start_next_frame(buffer, 
					      buflen, 
					      ts, 
					      ud);

  //
  // STEP 1 - isma decrypt. this returns ismacryp_rc_ok
  // whether the correct key is loaded or not.
  // nal is tested to determine if frame was decrypted OK 
  //
  ismacryprc = ismacrypDecryptSampleRemoveHeader(m_ismaCryptSId, 
					*buflen,
					*buffer,
					&temp_this_frame_size,
					&temp_buffer);

  if (ismacryprc != ismacryp_rc_ok ) {
    mp4f_message(LOG_ERR, "%s  2. decrypt error code:  %u" ,
	       m_name, ismacryprc);
    CHECK_AND_FREE(temp_buffer);
    // can't copy anything to buffer in this case.
    return ret; 
  }

  *buflen = temp_this_frame_size;
  memset(*buffer, 0, *buflen * sizeof(u_int8_t));
  memcpy(*buffer, temp_buffer, temp_this_frame_size);
  CHECK_AND_FREE(temp_buffer);

  // 
  // 	STEP 2 - H264 
  // 
  //    check the nal_len against frame size to validate
  //    the decryption and reject attempt to decrypt
  //    using wrong key 
  //
  if (*buffer != NULL && *buflen != 0) {
    if (m_buflen_size == 0) {
      m_parent->lock_file_mutex();
      MP4GetTrackH264LengthSize(m_parent->get_file(), m_track, &m_buflen_size);
      m_parent->unlock_file_mutex();
    }
#ifdef DEBUG_H264_NALS
    mp4f_message(LOG_DEBUG, "new frame - len %u", *buflen);
#endif
    do {
      nal_len = read_nal_size(*buffer + read_offset);
#ifdef DEBUG_H264_NALS
      mp4f_message(LOG_DEBUG, "nal offset %u fsize %u size %u", 
        read_offset, *buflen, nal_len);
#endif
      // test if nal is sensible.  this fails when 
      // wrong key is used to decrypt.  this test
      // avoids segfault below when bogus nal_len is used
      // to realloc m_translate_buffer
      if (nal_len != (*buflen - m_buflen_size))
      {
    	mp4f_message(LOG_ERR, "%s  3. buflen %u nal_len %u" ,
	       m_name, *buflen, nal_len);
        return (false);
      }

      len += nal_len + 3;
      read_offset += nal_len + m_buflen_size;
    } while (read_offset < *buflen);
    if (len > m_translate_buffer_size) {
      m_translate_buffer = (uint8_t *)realloc(m_translate_buffer, len);
      m_translate_buffer_size = len;
#ifdef DEBUG_H264_NALS
      mp4f_message(LOG_DEBUG, "buflen alloced as %u", len);
#endif
    }
    read_offset = 0;
    do {
      nal_len = read_nal_size(*buffer + read_offset);
#ifdef DEBUG_H264_NALS
      mp4f_message(LOG_DEBUG, "write offset %u, read offset %u len %u",
		   write_offset, read_offset, nal_len);
#endif
      m_translate_buffer[write_offset] = 0;
      m_translate_buffer[write_offset + 1] = 0;
      if (write_offset == 0) {
	// make sure that the first nal has a extra 0 (0 0 0 1 header)
	m_translate_buffer[2] = 0;
	write_offset = 1;
      }
      m_translate_buffer[write_offset + 2] = 1;
      memcpy(m_translate_buffer + write_offset + 3, 
	     *buffer + read_offset + m_buflen_size,
	     nal_len);
      write_offset += nal_len + 3;
      read_offset += nal_len + m_buflen_size;
    } while (read_offset < *buflen);
    *buffer = m_translate_buffer;
    *buflen = write_offset;
  }
  return ret;
}
AVCDescriptor* MP4Streamer::GetAVCDescriptor()
{
	uint8_t **sequenceHeader;
	uint8_t **pictureHeader;
	uint32_t *pictureHeaderSize;
	uint32_t *sequenceHeaderSize;
	uint32_t i;
	uint8_t profile, level;
	uint32_t len;
	
	//Check video
	if (!video || video->codec!=VideoCodec::H264)
		//Nothing
		return NULL;

	//Create descriptor
	AVCDescriptor* desc = new AVCDescriptor();

	//Set them
	desc->SetConfigurationVersion(0x01);
	desc->SetAVCProfileIndication(profile);
	desc->SetProfileCompatibility(0x00);
	desc->SetAVCLevelIndication(level);

	//Set nalu length
	MP4GetTrackH264LengthSize(video->mp4, video->track, &len);

	//Set it
	desc->SetNALUnitLength(len-1);

	// Get SEI informaMP4GetTrackH264SeqPictHeaderstion
	MP4GetTrackH264SeqPictHeaders(video->mp4, video->track, &sequenceHeader, &sequenceHeaderSize, &pictureHeader, &pictureHeaderSize);

	// Send sequence headers
	i=0;

	// Check we have sequence header
	if (sequenceHeader)
	{
		// Loop array
		while(sequenceHeader[i] && sequenceHeaderSize[i])
		{
			//Append sequence
			desc->AddSequenceParameterSet(sequenceHeader[i],sequenceHeaderSize[i]);
			//Update values based on the ones in SQS
			desc->SetAVCProfileIndication(sequenceHeader[i][1]);
			desc->SetProfileCompatibility(sequenceHeader[i][2]);
			desc->SetAVCLevelIndication(sequenceHeader[i][3]);
			//inc
			i++;
		}
	}

	// Send picture headers
	i=0;

	// Check we have picture header
	if (pictureHeader)
	{
		// Loop array
		while(pictureHeader[i] && pictureHeaderSize[i])
		{
			//Append sequence
			desc->AddPictureParameterSet(pictureHeader[i],pictureHeaderSize[i]);
			//inc
			i++;
		}
	}

	// Free data
	if (pictureHeader)
		free(pictureHeader);
	if (sequenceHeader)
		free(sequenceHeader);
	if (sequenceHeaderSize)
		free(sequenceHeaderSize);
	if (pictureHeaderSize)
		free(pictureHeaderSize);

	return desc;
}