예제 #1
0
vod_status_t
m3u8_builder_build_iframe_playlist(
	request_context_t* request_context,
	m3u8_config_t* conf,
	hls_muxer_conf_t* muxer_conf,
	vod_str_t* base_url,
	request_params_t* request_params,
	media_set_t* media_set,
	vod_str_t* result)
{
	hls_encryption_params_t encryption_params;
	write_segment_context_t ctx;
	segment_durations_t segment_durations;
	segmenter_conf_t* segmenter_conf = media_set->segmenter_conf;
	size_t iframe_length;
	size_t result_size;
	uint64_t duration_millis;
	uint32_t sequence_index;
	vod_status_t rc; 

	sequence_index = media_set->has_multi_sequences ? media_set->sequences[0].index : INVALID_SEQUENCE_INDEX;

	// iframes list is not supported with encryption, since:
	// 1. AES-128 - the IV of each key frame is not known in advance
	// 2. SAMPLE-AES - the layout of the TS files is not known in advance due to emulation prevention
	encryption_params.type = HLS_ENC_NONE;
	encryption_params.key = NULL;
	encryption_params.iv = NULL;

	// build the required tracks string
	rc = m3u8_builder_build_required_tracks_string(
		request_context, 
		media_set,
		sequence_index,
		request_params,
		&ctx.tracks_spec);
	if (rc != VOD_OK)
	{
		return rc;
	}

	// get segment durations
	if (segmenter_conf->align_to_key_frames)
	{
		rc = segmenter_get_segment_durations_accurate(
			request_context,
			segmenter_conf,
			media_set,
			NULL,
			MEDIA_TYPE_NONE,
			&segment_durations);
	}
	else
	{
		rc = segmenter_get_segment_durations_estimate(
			request_context,
			segmenter_conf,
			media_set,
			NULL,
			MEDIA_TYPE_NONE,
			&segment_durations);
	}

	if (rc != VOD_OK)
	{
		return rc;
	}

	duration_millis = segment_durations.end_time - segment_durations.start_time;
	iframe_length = sizeof("#EXTINF:.000,\n") - 1 + vod_get_int_print_len(vod_div_ceil(duration_millis, 1000)) +
		sizeof(byte_range_tag_format) + VOD_INT32_LEN + vod_get_int_print_len(MAX_FRAME_SIZE) - (sizeof("%uD%uD") - 1) +
		base_url->len + conf->segment_file_name_prefix.len + 1 + vod_get_int_print_len(segment_durations.segment_count) + ctx.tracks_spec.len + sizeof(".ts\n") - 1;

	result_size =
		conf->iframes_m3u8_header_len +
		iframe_length * media_set->sequences[0].video_key_frame_count +
		sizeof(m3u8_footer);

	// 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,
			"m3u8_builder_build_iframe_playlist: vod_alloc failed");
		return VOD_ALLOC_FAILED;
	}

	// fill out the buffer
	ctx.p = vod_copy(result->data, conf->iframes_m3u8_header, conf->iframes_m3u8_header_len);

	if (media_set->sequences[0].video_key_frame_count > 0)
	{
		ctx.base_url = base_url;
		ctx.segment_file_name_prefix = &conf->segment_file_name_prefix;
	
		rc = hls_muxer_simulate_get_iframes(
			request_context,
			&segment_durations, 
			muxer_conf,
			&encryption_params,
			media_set, 
			m3u8_builder_append_iframe_string, 
			&ctx);
		if (rc != VOD_OK)
		{
			return rc;
		}
	}

	ctx.p = vod_copy(ctx.p, m3u8_footer, sizeof(m3u8_footer) - 1);
	result->len = ctx.p - result->data;

	if (result->len > result_size)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"m3u8_builder_build_iframe_playlist: result length %uz exceeded allocated length %uz", 
			result->len, result_size);
		return VOD_UNEXPECTED;
	}
	
	return VOD_OK;
}
예제 #2
0
vod_status_t
m3u8_builder_build_iframe_playlist(
    request_context_t* request_context,
    m3u8_config_t* conf,
    vod_str_t* base_url,
    bool_t include_file_index,
    segmenter_conf_t* segmenter_conf,
    mpeg_metadata_t* mpeg_metadata,
    vod_str_t* result)
{
    write_segment_context_t ctx;
    size_t iframe_length;
    size_t result_size;
    hls_muxer_state_t muxer_state;
    bool_t simulation_supported;
    vod_status_t rc;
    uint32_t segment_count;

    // initialize the muxer
    rc = hls_muxer_init(&muxer_state, request_context, 0, mpeg_metadata, NULL, NULL, NULL, &simulation_supported);
    if (rc != VOD_OK)
    {
        return rc;
    }

    if (!simulation_supported)
    {
        vod_log_error(VOD_LOG_ERR, request_context->log, 0,
                      "m3u8_builder_build_iframe_playlist: simulation not supported for this file, cant create iframe playlist");
        return VOD_BAD_REQUEST;
    }

    // build the required tracks string
    rc = m3u8_builder_build_required_tracks_string(
             request_context,
             include_file_index,
             mpeg_metadata,
             &ctx.required_tracks);
    if (rc != VOD_OK)
    {
        return rc;
    }

    // calculate the required buffer length
    segment_count = segmenter_conf->get_segment_count(segmenter_conf, mpeg_metadata->duration_millis);
    if (segment_count == INVALID_SEGMENT_COUNT)
    {
        vod_log_error(VOD_LOG_ERR, request_context->log, 0,
                      "m3u8_builder_build_iframe_playlist: segment count is invalid");
        return VOD_BAD_DATA;
    }

    iframe_length = sizeof("#EXTINF:.000,\n") - 1 + m3u8_builder_get_int_print_len(vod_div_ceil(mpeg_metadata->duration_millis, 1000)) +
                    sizeof(byte_range_tag_format) + VOD_INT32_LEN + m3u8_builder_get_int_print_len(MAX_FRAME_SIZE) - (sizeof("%uD%uD") - 1) +
                    base_url->len + conf->segment_file_name_prefix.len + 1 + m3u8_builder_get_int_print_len(segment_count) + ctx.required_tracks.len + sizeof(".ts\n") - 1;

    result_size =
        conf->iframes_m3u8_header_len +
        iframe_length * mpeg_metadata->video_key_frame_count +
        sizeof(m3u8_footer);

    // 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,
                       "m3u8_builder_build_iframe_playlist: vod_alloc failed");
        return VOD_ALLOC_FAILED;
    }

    // fill out the buffer
    ctx.p = vod_copy(result->data, conf->iframes_m3u8_header, conf->iframes_m3u8_header_len);

    if (mpeg_metadata->video_key_frame_count > 0)
    {
        ctx.base_url = base_url;
        ctx.segment_file_name_prefix = &conf->segment_file_name_prefix;

        rc = hls_muxer_simulate_get_iframes(&muxer_state, segmenter_conf, mpeg_metadata, m3u8_builder_append_iframe_string, &ctx);
        if (rc != VOD_OK)
        {
            return rc;
        }
    }

    ctx.p = vod_copy(ctx.p, m3u8_footer, sizeof(m3u8_footer) - 1);
    result->len = ctx.p - result->data;

    if (result->len > result_size)
    {
        vod_log_error(VOD_LOG_ERR, request_context->log, 0,
                      "m3u8_builder_build_iframe_playlist: result length %uz exceeded allocated length %uz",
                      result->len, result_size);
        return VOD_UNEXPECTED;
    }

    return VOD_OK;
}