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; }
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"); } }
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; }