Пример #1
0
static vod_status_t
hls_muxer_init_id3_stream(
	hls_muxer_state_t* state,
	hls_muxer_conf_t* conf,
	mpegts_encoder_init_streams_state_t* init_streams_state)
{
	hls_muxer_stream_state_t* cur_stream;
	hls_muxer_stream_state_t* reference_stream;
	id3_context_t* context;
	vod_status_t rc;

	cur_stream = state->last_stream;

	// init the mpeg ts encoder
	rc = mpegts_encoder_init(
		&cur_stream->mpegts_encoder_state,
		init_streams_state,
		NULL,
		&state->queue,
		conf->interleave_frames,
		conf->align_frames);
	if (rc != VOD_OK)
	{
		return rc;
	}

	if (!conf->output_id3_timestamps)
	{
		return VOD_OK;
	}

	// get the stream that has the first frame
	rc = hls_muxer_choose_stream(state, &reference_stream);
	if (rc != VOD_OK)
	{
		if (rc == VOD_NOT_FOUND)
		{
			return VOD_OK;
		}
		return rc;
	}

	// allocate the context
	context = vod_alloc(state->request_context->pool, sizeof(*context));
	if (context == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0,
			"hls_muxer_init_id3_stream: vod_alloc failed");
		return VOD_ALLOC_FAILED;
	}

	// init the memory frames source
	rc = frames_source_memory_init(state->request_context, &cur_stream->cur_frame_part.frames_source_context);
	if (rc != VOD_OK)
	{
		return rc;
	}

	cur_stream->cur_frame_part.frames_source = &frames_source_memory;

	// base initialization
	cur_stream->media_type = MEDIA_TYPE_NONE;
	cur_stream->segment_limit = ULLONG_MAX;
	cur_stream->buffer_state = NULL;

	// init the id3 encoder
	id3_encoder_init(&context->encoder, &mpegts_encoder, &cur_stream->mpegts_encoder_state);

	cur_stream->top_filter = &id3_encoder;
	cur_stream->top_filter_context = &context->encoder;

	// copy the time stamps
	cur_stream->first_frame_time_offset = reference_stream->first_frame_time_offset;
	cur_stream->next_frame_time_offset = reference_stream->next_frame_time_offset;
	cur_stream->clip_from_frame_offset = reference_stream->clip_from_frame_offset;

	// init the frame part
	cur_stream->cur_frame = &context->frame;
	cur_stream->first_frame_part = &cur_stream->cur_frame_part;
	cur_stream->cur_frame_part.next = NULL;
	cur_stream->cur_frame_part.first_frame = &context->frame;
	cur_stream->cur_frame_part.last_frame = &context->frame + 1;
	cur_stream->source = NULL;

	// init the frame
	context->frame.size = vod_sprintf(context->data, ID3_TEXT_JSON_FORMAT,
		hls_rescale_to_millis(cur_stream->first_frame_time_offset)) - context->data;
	context->frame.duration = 0;
	context->frame.key_frame = 1;
	context->frame.pts_delay = 0;
	context->frame.offset = (uintptr_t)&context->data;

	state->last_stream++;

	return VOD_OK;
}
Пример #2
0
static vod_status_t 
audio_filter_update_track(audio_filter_state_t* state)
{
	media_track_t* output = state->output;
	input_frame_t* cur_frame;
	input_frame_t* last_frame;
	uint32_t old_timescale;
	vod_status_t rc;
	u_char* new_extra_data;
	bool_t has_frames;

	if (state->sink.encoder->time_base.num != 1)
	{
		vod_log_error(VOD_LOG_ERR, state->request_context->log, 0,
			"audio_filter_update_track: unexpected encoder time base %d/%d", 
			state->sink.encoder->time_base.num, state->sink.encoder->time_base.den);
		return VOD_UNEXPECTED;
	}

	// decrement the old frame count and size
	state->sequence->total_frame_count -= output->frame_count;
	state->sequence->total_frame_size -= output->total_frames_size;
	output->total_frames_size = 0;
	output->total_frames_duration = 0;

	// update frames
	output->frame_count = state->frames_array.nelts;

	output->frames.first_frame = state->frames_array.elts;
	output->frames.last_frame = output->frames.first_frame + output->frame_count;
	output->frames.next = NULL;

	// check whether there are any frames with duration
	has_frames = FALSE;
	
	// Note: always a single part here
	last_frame = output->frames.last_frame;
	for (cur_frame = output->frames.first_frame; cur_frame < last_frame; cur_frame++)
	{
		if (cur_frame->duration != 0)
		{
			has_frames = TRUE;
			break;
		}
	}

	if (!has_frames)
	{
		output->frames.first_frame = NULL;
		output->frames.last_frame = NULL;
		output->frame_count = 0;
		return VOD_OK;
	}
	
	// update the frames source to memory
	rc = frames_source_memory_init(state->request_context, &output->frames.frames_source_context);
	if (rc != VOD_OK)
	{
		return rc;
	}

	output->frames.frames_source = &frames_source_memory;

	// calculate the total frames size and duration
	output->media_info.min_frame_duration = 0;
	
	for (cur_frame = output->frames.first_frame; cur_frame < last_frame; cur_frame++)
	{
		output->total_frames_size += cur_frame->size;
		output->total_frames_duration += cur_frame->duration;
		
		if (cur_frame->duration != 0 && 
			(output->media_info.min_frame_duration == 0 || cur_frame->duration < output->media_info.min_frame_duration))
		{
			output->media_info.min_frame_duration = cur_frame->duration;
		}
	}
	
	// update media info
	old_timescale = output->media_info.timescale;
	output->media_info.timescale = state->sink.encoder->time_base.den;
	output->media_info.duration = rescale_time(output->media_info.duration, old_timescale, output->media_info.timescale);
	output->media_info.bitrate = state->sink.encoder->bit_rate;
	
	output->media_info.u.audio.object_type_id = 0x40;		// ffmpeg always writes 0x40 (ff_mp4_obj_type)
	output->media_info.u.audio.channels = state->sink.encoder->channels;
	output->media_info.u.audio.bits_per_sample = ENCODER_BITS_PER_SAMPLE;
	output->media_info.u.audio.packet_size = 0;				// ffmpeg always writes 0 (mov_write_audio_tag)
	output->media_info.u.audio.sample_rate = state->sink.encoder->sample_rate;
	
	output->key_frame_count = 0;
	output->first_frame_time_offset = rescale_time(output->first_frame_time_offset, old_timescale, output->media_info.timescale);
	
	new_extra_data = vod_alloc(state->request_context->pool, state->sink.encoder->extradata_size);
	if (new_extra_data == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->request_context->log, 0,
			"audio_filter_update_track: vod_alloc failed");
		return VOD_ALLOC_FAILED;
	}
	vod_memcpy(new_extra_data, state->sink.encoder->extradata, state->sink.encoder->extradata_size);
	
	output->media_info.extra_data.data = new_extra_data;
	output->media_info.extra_data.len = state->sink.encoder->extradata_size;

	if (output->media_info.codec_name.data != NULL)
	{
		rc = codec_config_get_audio_codec_name(state->request_context, &output->media_info);
		if (rc != VOD_OK)
		{
			return rc;
		}
	}
		
	// add the new frame count and size
	state->sequence->total_frame_count += output->frame_count;
	state->sequence->total_frame_size += output->total_frames_size;

	// TODO: update raw_atoms
	
	return VOD_OK;
}