Exemplo n.º 1
0
vod_status_t
audio_filter_alloc_state(
	request_context_t* request_context,
	media_sequence_t* sequence,
	media_clip_t* clip,
	media_track_t* output_track,
	size_t* cache_buffer_count,
	void** result)
{
	audio_filter_init_context_t init_context;
	u_char filter_name[VOD_INT32_LEN + 1];
	audio_filter_state_t* state;
	vod_pool_cleanup_t *cln;
	AVFilterInOut *outputs = NULL;
	AVFilterInOut *inputs = NULL;
	uint32_t initial_alloc_size;
	vod_status_t rc;
	int avrc;

	if (!initialized)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: module failed to initialize successfully");
		return VOD_UNEXPECTED;
	}

	// get the source count and graph desc size
	init_context.request_context = request_context;
	init_context.graph_desc_size = 0;
	init_context.source_count = 0;
	init_context.output_frame_count = 0;

	rc = audio_filter_walk_filters_prepare_init(&init_context, &clip, 100, 100);
	if (rc != VOD_OK)
	{
		return rc;
	}

	if (clip == NULL || init_context.source_count <= 0)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: unexpected - no sources found");
		return VOD_UNEXPECTED;
	}

	if (clip->type == MEDIA_CLIP_SOURCE)
	{
		// got left with a source, following a mix of a single source, nothing to do
		return VOD_OK;
	}

	if (init_context.output_frame_count > MAX_FRAME_COUNT)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: expected output frame count %uD too big", init_context.output_frame_count);
		return VOD_BAD_REQUEST;
	}

	// allocate the state
	state = vod_alloc(request_context->pool, sizeof(*state));
	if (state == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_alloc failed");
		return VOD_ALLOC_FAILED;
	}
	vod_memzero(state, sizeof(*state));
	
	// add to the cleanup pool
	cln = vod_pool_cleanup_add(request_context->pool, 0);
	if (cln == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_pool_cleanup_add failed");
		return VOD_ALLOC_FAILED;
	}

	cln->handler = audio_filter_free_state;
	cln->data = state;

	// allocate the filter graph
	state->filter_graph = avfilter_graph_alloc();
	if (state->filter_graph == NULL)
	{
		vod_log_error(VOD_LOG_ERR, state->request_context->log, 0,
			"audio_filter_alloc_state: avfilter_graph_alloc failed");
		return VOD_ALLOC_FAILED;
	}

	// allocate the graph desc and sources
	init_context.graph_desc = vod_alloc(request_context->pool, init_context.graph_desc_size + 
		sizeof(state->sources[0]) * init_context.source_count);
	if (init_context.graph_desc == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_alloc failed (1)");
		return VOD_ALLOC_FAILED;
	}

	state->sources = (void*)(init_context.graph_desc + init_context.graph_desc_size);
	state->sources_end = state->sources + init_context.source_count;
	vod_memzero(state->sources, (u_char*)state->sources_end - (u_char*)state->sources);

	// initialize the sources and the graph description
	init_context.filter_graph = state->filter_graph;
	init_context.outputs = &outputs;
	init_context.cur_source = state->sources;
	init_context.graph_desc_pos = init_context.graph_desc;
	init_context.max_frame_size = 0;
	init_context.cache_slot_id = 0;

	rc = audio_filter_init_sources_and_graph_desc(&init_context, clip);
	if (rc != VOD_OK)
	{
		goto end;
	}

	*init_context.graph_desc_pos = '\0';

	// initialize the sink
	vod_sprintf(filter_name, "%uD%Z", clip->id);

	rc = audio_filter_init_sink(
		request_context,
		state->filter_graph,
		output_track,
		filter_name,
		&state->sink,
		&inputs);
	if (rc != VOD_OK)
	{
		goto end;
	}

	// parse the graph description
	avrc = avfilter_graph_parse_ptr(state->filter_graph, (char*)init_context.graph_desc, &inputs, &outputs, NULL);
	if (avrc < 0)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: avfilter_graph_parse_ptr failed %d", avrc);
		rc = VOD_UNEXPECTED;
		goto end;
	}

	// validate and configure the graph
	avrc = avfilter_graph_config(state->filter_graph, NULL);
	if (avrc < 0)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: avfilter_graph_config failed %d", avrc);
		rc = VOD_UNEXPECTED;
		goto end;
	}

	// set the buffer sink frame size
	if ((state->sink.encoder->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) == 0)
	{
		av_buffersink_set_frame_size(state->sink.buffer_sink, state->sink.encoder->frame_size);
	}
	
	// allocate frames
	state->decoded_frame = av_frame_alloc();
	if (state->decoded_frame == NULL)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: av_frame_alloc failed (1)");
		return VOD_ALLOC_FAILED;
	}
	state->filtered_frame = av_frame_alloc();
	if (state->filtered_frame == NULL)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: av_frame_alloc failed (2)");
		return VOD_ALLOC_FAILED;
	}

	// allocate the frame buffer
	state->frame_buffer = vod_alloc(request_context->pool, init_context.max_frame_size);
	if (state->frame_buffer == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_alloc failed (2)");
		rc = VOD_ALLOC_FAILED;
		goto end;
	}

	// initialize the output arrays
	initial_alloc_size = init_context.output_frame_count + 10;

	if (vod_array_init(&state->frames_array, request_context->pool, initial_alloc_size, sizeof(input_frame_t)) != VOD_OK)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_array_init failed (1)");
		return VOD_ALLOC_FAILED;
	}

	state->request_context = request_context;
	state->sequence = sequence;
	state->output = output_track;
	state->cur_frame_pos = 0;
	state->first_time = TRUE;
	state->cur_source = NULL;

	*cache_buffer_count = init_context.cache_slot_id;
	*result = state;

end:

	avfilter_inout_free(&inputs);
	avfilter_inout_free(&outputs);

	return rc;
}
Exemplo n.º 2
0
vod_status_t
audio_filter_alloc_state(
	request_context_t* request_context,
	mpeg_stream_metadata_t* stream_metadata,
	void** result)
{
	char filter_desc[sizeof(ATEMPO_FILTER_DESCRIPTION) + 2 * VOD_INT64_LEN];
	audio_filter_state_t* state;
	uint32_t initial_alloc_size;
	mp4a_config_t codec_config;
	vod_status_t rc;
	int ret;
	
	if (!initialized)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: module failed to initialize successfully");
		return VOD_UNEXPECTED;
	}

	if (stream_metadata->media_info.speed_denom != 10)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: unexpected speed denom, must be 10");
		return VOD_UNEXPECTED;
	}

	// parse the codec config
	rc = codec_config_mp4a_config_parse(
		request_context, 
		stream_metadata->media_info.extra_data,
		stream_metadata->media_info.extra_data_size,
		&codec_config);
	if (rc != VOD_OK)
	{
		return rc;
	}

	// allocate the state
	state = vod_alloc(request_context->pool, sizeof(*state));
	if (state == NULL)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_alloc failed");
		return VOD_ALLOC_FAILED;
	}
	vod_memzero(state, sizeof(*state));
	
	state->request_context = request_context;
	state->speed_nom = stream_metadata->media_info.speed_nom;
	state->speed_denom = stream_metadata->media_info.speed_denom;
	state->output = stream_metadata;

	// init the decoder	
	state->decoder = avcodec_alloc_context3(decoder_codec);
	if (state->decoder == NULL)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: avcodec_alloc_context3 failed (1)");
		rc = VOD_ALLOC_FAILED;
		goto error;
	}

	state->decoder->codec_tag = stream_metadata->media_info.format;
	state->decoder->bit_rate = stream_metadata->media_info.bitrate;
	state->decoder->time_base.num = 1;
	// Note: changing the timescale in order to revert the speed change that was applied to the frames while parsing the mp4
	state->decoder->time_base.den = stream_metadata->media_info.timescale / stream_metadata->media_info.speed_nom * stream_metadata->media_info.speed_denom;
	state->decoder->pkt_timebase = state->decoder->time_base;
	state->decoder->extradata = (u_char*)stream_metadata->media_info.extra_data;
	state->decoder->extradata_size = stream_metadata->media_info.extra_data_size;
	state->decoder->channels = stream_metadata->media_info.u.audio.channels;
	state->decoder->bits_per_coded_sample = stream_metadata->media_info.u.audio.bits_per_sample;
	state->decoder->sample_rate = stream_metadata->media_info.u.audio.sample_rate;
	state->decoder->channel_layout = 0;
	if (codec_config.channel_config < ARRAY_ENTRIES(aac_channel_layout))
	{
		state->decoder->channel_layout = aac_channel_layout[codec_config.channel_config];
	}
	
	ret = avcodec_open2(state->decoder, decoder_codec, NULL);
	if (ret < 0) 
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: avcodec_open2(decoder) failed %d", ret);
		rc = VOD_UNEXPECTED;
		goto error;
	}
	
	// init the encoder
	state->encoder = avcodec_alloc_context3(encoder_codec);
	if (state->encoder == NULL) 
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: avcodec_alloc_context3 failed (2)");
		rc = VOD_ALLOC_FAILED;
		goto error;
	}

	state->encoder->sample_fmt = ENCODER_INPUT_SAMPLE_FORMAT;
	state->encoder->sample_rate = state->decoder->sample_rate;
	state->encoder->channel_layout = state->decoder->channel_layout;
	state->encoder->channels = state->decoder->channels;
	state->encoder->bit_rate = state->decoder->bit_rate;
	state->encoder->flags |= CODEC_FLAG_GLOBAL_HEADER;		// make the codec generate the extra data

	ret = avcodec_open2(state->encoder, encoder_codec, NULL);
	if (ret < 0) 
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: avcodec_open2(encoder) failed %d", ret);
		rc = VOD_UNEXPECTED;
		goto error;
	}
	
	// allocate frames
	state->decoded_frame = av_frame_alloc();
	if (state->decoded_frame == NULL)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: av_frame_alloc failed (1)");
		rc = VOD_ALLOC_FAILED;
		goto error;
	}
	state->filtered_frame = av_frame_alloc();
	if (state->filtered_frame == NULL)
	{
		vod_log_error(VOD_LOG_ERR, request_context->log, 0,
			"audio_filter_alloc_state: av_frame_alloc failed (2)");
		rc = VOD_ALLOC_FAILED;
		goto error;
	}

	// initialize the output arrays
	initial_alloc_size = (stream_metadata->frame_count * stream_metadata->media_info.speed_denom) / stream_metadata->media_info.speed_nom + 10;
	
	if (vod_array_init(&state->frames_array, request_context->pool, initial_alloc_size, sizeof(input_frame_t)) != VOD_OK)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_array_init failed (1)");
		rc = VOD_ALLOC_FAILED;
		goto error;
	}
	
	if (vod_array_init(&state->frame_offsets_array, request_context->pool, initial_alloc_size, sizeof(uint64_t)) != VOD_OK)
	{
		vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0,
			"audio_filter_alloc_state: vod_array_init failed (2)");
		rc = VOD_ALLOC_FAILED;
		goto error;
	}
	
	// initialize the filter graph
	vod_sprintf(filter_desc, 
		ATEMPO_FILTER_DESCRIPTION, 
		(int)(stream_metadata->media_info.speed_nom / 10), 
		(int)(stream_metadata->media_info.speed_nom % 10));

	rc = audio_filter_init_filters(state, stream_metadata, filter_desc);
	if (rc != VOD_OK)
	{
		goto error;
	}
	
	*result = state;
	
	return VOD_OK;

error:

	audio_filter_free_state(state);

	return rc;
}