| @@ -69,6 +69,28 @@ typedef struct { | |||||
| return AVERROR(EINVAL);\ | return AVERROR(EINVAL);\ | ||||
| } | } | ||||
| static int insert_filter(BufferSourceContext *abuffer, | |||||
| AVFilterLink *link, AVFilterContext **filt_ctx, | |||||
| const char *filt_name); | |||||
| static void remove_filter(AVFilterContext **filt_ctx); | |||||
| static int reconfigure_filter(BufferSourceContext *abuffer, AVFilterContext *filt_ctx); | |||||
| static inline void log_input_change(void *ctx, AVFilterLink *link, AVFilterBufferRef *ref) | |||||
| { | |||||
| char old_layout_str[16], new_layout_str[16]; | |||||
| av_get_channel_layout_string(old_layout_str, sizeof(old_layout_str), | |||||
| -1, link->channel_layout); | |||||
| av_get_channel_layout_string(new_layout_str, sizeof(new_layout_str), | |||||
| -1, ref->audio->channel_layout); | |||||
| av_log(ctx, AV_LOG_INFO, | |||||
| "Audio input format changed: " | |||||
| "%s:%s:%d -> %s:%s:%d, normalizing\n", | |||||
| av_get_sample_fmt_name(link->format), | |||||
| old_layout_str, (int)link->sample_rate, | |||||
| av_get_sample_fmt_name(ref->format), | |||||
| new_layout_str, ref->audio->sample_rate); | |||||
| } | |||||
| static int check_format_change_video(AVFilterContext *buffer_filter, | static int check_format_change_video(AVFilterContext *buffer_filter, | ||||
| AVFilterBufferRef *picref) | AVFilterBufferRef *picref) | ||||
| { | { | ||||
| @@ -122,12 +144,72 @@ static int check_format_change_video(AVFilterContext *buffer_filter, | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int check_format_change_audio(AVFilterContext *ctx, | |||||
| AVFilterBufferRef *samplesref) | |||||
| { | |||||
| BufferSourceContext *abuffer = ctx->priv; | |||||
| AVFilterLink *link; | |||||
| int ret, logged = 0; | |||||
| link = ctx->outputs[0]; | |||||
| if (samplesref->audio->sample_rate != link->sample_rate) { | |||||
| log_input_change(ctx, link, samplesref); | |||||
| logged = 1; | |||||
| abuffer->sample_rate = samplesref->audio->sample_rate; | |||||
| if (!abuffer->aresample) { | |||||
| ret = insert_filter(abuffer, link, &abuffer->aresample, "aresample"); | |||||
| if (ret < 0) return ret; | |||||
| } else { | |||||
| link = abuffer->aresample->outputs[0]; | |||||
| if (samplesref->audio->sample_rate == link->sample_rate) | |||||
| remove_filter(&abuffer->aresample); | |||||
| else | |||||
| if ((ret = reconfigure_filter(abuffer, abuffer->aresample)) < 0) | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| link = ctx->outputs[0]; | |||||
| if (samplesref->format != link->format || | |||||
| samplesref->audio->channel_layout != link->channel_layout || | |||||
| samplesref->audio->planar != link->planar) { | |||||
| if (!logged) log_input_change(ctx, link, samplesref); | |||||
| abuffer->sample_format = samplesref->format; | |||||
| abuffer->channel_layout = samplesref->audio->channel_layout; | |||||
| abuffer->packing_format = samplesref->audio->planar; | |||||
| if (!abuffer->aconvert) { | |||||
| ret = insert_filter(abuffer, link, &abuffer->aconvert, "aconvert"); | |||||
| if (ret < 0) return ret; | |||||
| } else { | |||||
| link = abuffer->aconvert->outputs[0]; | |||||
| if (samplesref->format == link->format && | |||||
| samplesref->audio->channel_layout == link->channel_layout && | |||||
| samplesref->audio->planar == link->planar | |||||
| ) | |||||
| remove_filter(&abuffer->aconvert); | |||||
| else | |||||
| if ((ret = reconfigure_filter(abuffer, abuffer->aconvert)) < 0) | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int check_format_change(AVFilterContext *buffer_filter, | static int check_format_change(AVFilterContext *buffer_filter, | ||||
| AVFilterBufferRef *picref) | AVFilterBufferRef *picref) | ||||
| { | { | ||||
| switch (buffer_filter->outputs[0]->type) { | switch (buffer_filter->outputs[0]->type) { | ||||
| case AVMEDIA_TYPE_VIDEO: | case AVMEDIA_TYPE_VIDEO: | ||||
| return check_format_change_video(buffer_filter, picref); | return check_format_change_video(buffer_filter, picref); | ||||
| case AVMEDIA_TYPE_AUDIO: | |||||
| return check_format_change_audio(buffer_filter, picref); | |||||
| default: | default: | ||||
| return AVERROR(ENOSYS); | return AVERROR(ENOSYS); | ||||
| } | } | ||||
| @@ -484,29 +566,12 @@ static void remove_filter(AVFilterContext **filt_ctx) | |||||
| set_link_source(src, outlink); | set_link_source(src, outlink); | ||||
| } | } | ||||
| static inline void log_input_change(void *ctx, AVFilterLink *link, AVFilterBufferRef *ref) | |||||
| { | |||||
| char old_layout_str[16], new_layout_str[16]; | |||||
| av_get_channel_layout_string(old_layout_str, sizeof(old_layout_str), | |||||
| -1, link->channel_layout); | |||||
| av_get_channel_layout_string(new_layout_str, sizeof(new_layout_str), | |||||
| -1, ref->audio->channel_layout); | |||||
| av_log(ctx, AV_LOG_INFO, | |||||
| "Audio input format changed: " | |||||
| "%s:%s:%d -> %s:%s:%d, normalizing\n", | |||||
| av_get_sample_fmt_name(link->format), | |||||
| old_layout_str, (int)link->sample_rate, | |||||
| av_get_sample_fmt_name(ref->format), | |||||
| new_layout_str, ref->audio->sample_rate); | |||||
| } | |||||
| int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx, | int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx, | ||||
| AVFilterBufferRef *samplesref, | AVFilterBufferRef *samplesref, | ||||
| int av_unused flags) | int av_unused flags) | ||||
| { | { | ||||
| BufferSourceContext *abuffer = ctx->priv; | BufferSourceContext *abuffer = ctx->priv; | ||||
| AVFilterLink *link; | |||||
| int ret, logged = 0; | |||||
| int ret; | |||||
| if (av_fifo_space(abuffer->fifo) < sizeof(samplesref)) { | if (av_fifo_space(abuffer->fifo) < sizeof(samplesref)) { | ||||
| av_log(ctx, AV_LOG_ERROR, | av_log(ctx, AV_LOG_ERROR, | ||||
| @@ -515,55 +580,9 @@ int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx, | |||||
| return AVERROR(EINVAL); | return AVERROR(EINVAL); | ||||
| } | } | ||||
| // Normalize input | |||||
| link = ctx->outputs[0]; | |||||
| if (samplesref->audio->sample_rate != link->sample_rate) { | |||||
| log_input_change(ctx, link, samplesref); | |||||
| logged = 1; | |||||
| abuffer->sample_rate = samplesref->audio->sample_rate; | |||||
| if (!abuffer->aresample) { | |||||
| ret = insert_filter(abuffer, link, &abuffer->aresample, "aresample"); | |||||
| if (ret < 0) return ret; | |||||
| } else { | |||||
| link = abuffer->aresample->outputs[0]; | |||||
| if (samplesref->audio->sample_rate == link->sample_rate) | |||||
| remove_filter(&abuffer->aresample); | |||||
| else | |||||
| if ((ret = reconfigure_filter(abuffer, abuffer->aresample)) < 0) | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| link = ctx->outputs[0]; | |||||
| if (samplesref->format != link->format || | |||||
| samplesref->audio->channel_layout != link->channel_layout || | |||||
| samplesref->audio->planar != link->planar) { | |||||
| if (!logged) log_input_change(ctx, link, samplesref); | |||||
| abuffer->sample_format = samplesref->format; | |||||
| abuffer->channel_layout = samplesref->audio->channel_layout; | |||||
| abuffer->packing_format = samplesref->audio->planar; | |||||
| if (!abuffer->aconvert) { | |||||
| ret = insert_filter(abuffer, link, &abuffer->aconvert, "aconvert"); | |||||
| if (ret < 0) return ret; | |||||
| } else { | |||||
| link = abuffer->aconvert->outputs[0]; | |||||
| if (samplesref->format == link->format && | |||||
| samplesref->audio->channel_layout == link->channel_layout && | |||||
| samplesref->audio->planar == link->planar | |||||
| ) | |||||
| remove_filter(&abuffer->aconvert); | |||||
| else | |||||
| if ((ret = reconfigure_filter(abuffer, abuffer->aconvert)) < 0) | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| ret = check_format_change(ctx, samplesref); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| if (sizeof(samplesref) != av_fifo_generic_write(abuffer->fifo, &samplesref, | if (sizeof(samplesref) != av_fifo_generic_write(abuffer->fifo, &samplesref, | ||||
| sizeof(samplesref), NULL)) { | sizeof(samplesref), NULL)) { | ||||