上一篇提到的命令行实现混音处理,这篇文章主要从源码角度理解混音处理的细节,源码在\libavfilter\af_amix.c文件,
核心处理逻辑在以下函数,看注释,从输入的FIFOs中读取样本,混合,写到到输出的AVFilterLink
/**
* Read samples from the input FIFOs, mix, and write to the output link.
*/
static int output_frame(AVFilterLink *outlink)
其中数据处理在以下循环中,用av_audio_fifo_read从各个输入的FIFOs中读取数据,保存到AVFrame的extended_data中,然后进行向量的乘法处理(vector_fmac_scalar或者vector_dmac_scalar)。
for (i = 0; i < s->nb_inputs; i++) {
if (s->input_state[i] & INPUT_ON) {
int planes, plane_size, p;
av_audio_fifo_read(s->fifos[i], (void **)in_buf->extended_data,
nb_samples);
planes = s->planar ? s->nb_channels : 1;
plane_size = nb_samples * (s->planar ? 1 : s->nb_channels);
plane_size = FFALIGN(plane_size, 16);
if (out_buf->format == AV_SAMPLE_FMT_FLT ||
out_buf->format == AV_SAMPLE_FMT_FLTP) {
for (p = 0; p < planes; p++) {
s->fdsp->vector_fmac_scalar((float *)out_buf->extended_data[p],
(float *) in_buf->extended_data[p],
s->input_scale[i], plane_size);
}
} else {
for (p = 0; p < planes; p++) {
s->fdsp->vector_dmac_scalar((double *)out_buf->extended_data[p],
(double *) in_buf->extended_data[p],
s->input_scale[i], plane_size);
}
}
}
}
函数的最后执行ff_filter_frame(outlink, out_buf);这个函数在avfilter.c文件中,
int ff_filter_frame(AVFilterLink *link, AVFrame *frame),该函数中核心的处理在于 ret = ff_framequeue_add(&link->fifo, frame);在framequeue.c文件中
int ff_framequeue_add(FFFrameQueue *fq, AVFrame *frame)
{
FFFrameBucket *b;
check_consistency(fq);
if (fq->queued == fq->allocated) {
if (fq->allocated == 1) {
size_t na = 8;
FFFrameBucket *nq = av_realloc_array(NULL, na, sizeof(*nq));
if (!nq)
return AVERROR(ENOMEM);
nq[0] = fq->queue[0];
fq->queue = nq;
fq->allocated = na;
} else {
size_t na = fq->allocated << 1;
FFFrameBucket *nq = av_realloc_array(fq->queue, na, sizeof(*nq));
if (!nq)
return AVERROR(ENOMEM);
if (fq->tail + fq->queued > fq->allocated)
memmove(nq + fq->allocated, nq,
(fq->tail + fq->queued - fq->allocated) * sizeof(*nq));
fq->queue = nq;
fq->allocated = na;
}
}
b = bucket(fq, fq->queued);
b->frame = frame;
fq->queued++;
fq->total_frames_head++;
fq->total_samples_head += frame->nb_samples;
check_consistency(fq);
return 0;
}