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