vod_status_t mss_packager_build_fragment_header( request_context_t* request_context, mpeg_stream_metadata_t* stream_metadata, uint32_t segment_index, size_t extra_traf_atoms_size, write_extra_traf_atoms_callback_t write_extra_traf_atoms_callback, void* write_extra_traf_atoms_context, bool_t size_only, vod_str_t* result, size_t* total_fragment_size) { input_frame_t* last_frame; input_frame_t* cur_frame; size_t mdat_atom_size; size_t trun_atom_size; size_t moof_atom_size; size_t traf_atom_size; size_t result_size; u_char* p; // calculate sizes mdat_atom_size = ATOM_HEADER_SIZE + stream_metadata->total_frames_size; trun_atom_size = mp4_builder_get_trun_atom_size(stream_metadata->media_info.media_type, stream_metadata->frame_count); traf_atom_size = ATOM_HEADER_SIZE + ATOM_HEADER_SIZE + sizeof(tfhd_atom_t) + trun_atom_size + ATOM_HEADER_SIZE + sizeof(uuid_tfxd_atom_t) + extra_traf_atoms_size; moof_atom_size = ATOM_HEADER_SIZE + ATOM_HEADER_SIZE + sizeof(mfhd_atom_t)+ traf_atom_size; result_size = moof_atom_size + ATOM_HEADER_SIZE; // mdat *total_fragment_size = result_size + stream_metadata->total_frames_size; // head request optimization if (size_only) { return VOD_OK; } // allocate the buffer result->data = vod_alloc(request_context->pool, result_size); if (result->data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "mss_packager_build_fragment_header: vod_alloc failed"); return VOD_ALLOC_FAILED; } p = result->data; // moof write_atom_header(p, moof_atom_size, 'm', 'o', 'o', 'f'); // moof.mfhd p = mp4_builder_write_mfhd_atom(p, segment_index); // moof.traf write_atom_header(p, traf_atom_size, 't', 'r', 'a', 'f'); // moof.traf.tfhd switch (stream_metadata->media_info.media_type) { case MEDIA_TYPE_VIDEO: p = mss_write_tfhd_atom(p, stream_metadata->media_info.track_id, 0x01010000); break; case MEDIA_TYPE_AUDIO: p = mss_write_tfhd_atom(p, stream_metadata->media_info.track_id, 0x02000000); break; } // moof.traf.trun last_frame = stream_metadata->frames + stream_metadata->frame_count; for (cur_frame = stream_metadata->frames; cur_frame < last_frame; cur_frame++) { cur_frame->duration = rescale_time(cur_frame->duration, stream_metadata->media_info.timescale, MSS_TIMESCALE); } p = mp4_builder_write_trun_atom( p, stream_metadata->media_info.media_type, stream_metadata->frames, stream_metadata->frame_count, moof_atom_size + ATOM_HEADER_SIZE); p = mss_write_uuid_tfxd_atom(p, stream_metadata); // moof.traf.xxx if (write_extra_traf_atoms_callback != NULL) { p = write_extra_traf_atoms_callback(write_extra_traf_atoms_context, p, moof_atom_size + ATOM_HEADER_SIZE); } // mdat write_atom_header(p, mdat_atom_size, 'm', 'd', 'a', 't'); result->len = p - result->data; if (result->len != result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "mss_packager_build_fragment_header: result length %uz is different than allocated length %uz", result->len, result_size); return VOD_UNEXPECTED; } return VOD_OK; }
vod_status_t mss_packager_build_fragment_header( request_context_t* request_context, media_set_t* media_set, uint32_t segment_index, size_t extra_traf_atoms_size, mss_write_extra_traf_atoms_callback_t write_extra_traf_atoms_callback, void* write_extra_traf_atoms_context, bool_t size_only, vod_str_t* result, size_t* total_fragment_size) { segment_timing_info_t timing_info; media_clip_filtered_t* cur_clip; media_sequence_t* sequence = media_set->sequences; input_frame_t* last_frame; input_frame_t* cur_frame; media_track_t* first_track = sequence->filtered_clips[0].first_track; media_track_t* track; uint32_t media_type = sequence->media_type; size_t mdat_atom_size; size_t trun_atom_size; size_t moof_atom_size; size_t traf_atom_size; size_t result_size; u_char* p; // calculate sizes mdat_atom_size = ATOM_HEADER_SIZE + sequence->total_frame_size; trun_atom_size = mp4_builder_get_trun_atom_size(media_type, sequence->total_frame_count); traf_atom_size = ATOM_HEADER_SIZE + ATOM_HEADER_SIZE + sizeof(tfhd_atom_t) + trun_atom_size + ATOM_HEADER_SIZE + sizeof(uuid_tfxd_atom_t) + extra_traf_atoms_size; if (media_set->type == MEDIA_SET_LIVE) { traf_atom_size += TFRF_ATOM_SIZE; } moof_atom_size = ATOM_HEADER_SIZE + ATOM_HEADER_SIZE + sizeof(mfhd_atom_t)+ traf_atom_size; result_size = moof_atom_size + ATOM_HEADER_SIZE; // mdat *total_fragment_size = result_size + sequence->total_frame_size; // head request optimization if (size_only) { return VOD_OK; } // allocate the buffer result->data = vod_alloc(request_context->pool, result_size); if (result->data == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "mss_packager_build_fragment_header: vod_alloc failed"); return VOD_ALLOC_FAILED; } p = result->data; // moof write_atom_header(p, moof_atom_size, 'm', 'o', 'o', 'f'); // moof.mfhd p = mp4_builder_write_mfhd_atom(p, segment_index); // moof.traf write_atom_header(p, traf_atom_size, 't', 'r', 'a', 'f'); // moof.traf.tfhd switch (media_type) { case MEDIA_TYPE_VIDEO: p = mss_write_tfhd_atom(p, first_track->media_info.track_id, 0x01010000); break; case MEDIA_TYPE_AUDIO: p = mss_write_tfhd_atom(p, first_track->media_info.track_id, 0x02000000); break; } // moof.traf.trun for (cur_clip = sequence->filtered_clips; cur_clip < sequence->filtered_clips_end; cur_clip++) { track = cur_clip->first_track; cur_frame = track->first_frame; last_frame = track->last_frame; for (; cur_frame < last_frame; cur_frame++) { cur_frame->duration = rescale_time(cur_frame->duration, track->media_info.timescale, MSS_TIMESCALE); cur_frame->pts_delay = rescale_time(cur_frame->pts_delay, track->media_info.timescale, MSS_TIMESCALE); } } p = mp4_builder_write_trun_atom( p, sequence, moof_atom_size + ATOM_HEADER_SIZE); if (media_set->type == MEDIA_SET_LIVE) { // using only estimate timing info in live, since we don't have the accurate timing // for the lookahead segments. the timestamp has to be consistent between segments/manifest // otherwise some segments may be pulled more than once timing_info.timestamp = mss_rescale_millis(media_set->segment_start_time); timing_info.duration = mss_rescale_millis(media_set->segmenter_conf->segment_duration); p = mss_write_uuid_tfxd_atom(p, &timing_info); p = mss_write_uuid_tfrf_atom(p, &timing_info); } else { mss_get_segment_timing_info(sequence, &timing_info); p = mss_write_uuid_tfxd_atom(p, &timing_info); } // moof.traf.xxx if (write_extra_traf_atoms_callback != NULL) { p = write_extra_traf_atoms_callback(write_extra_traf_atoms_context, p, moof_atom_size); } // mdat write_atom_header(p, mdat_atom_size, 'm', 'd', 'a', 't'); result->len = p - result->data; if (result->len != result_size) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "mss_packager_build_fragment_header: result length %uz is different than allocated length %uz", result->len, result_size); return VOD_UNEXPECTED; } return VOD_OK; }