Exemple #1
0
int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
{
    int use_generic = 1;
    int len         = in->nb_samples;
    int p;

    if (ac->dc) {
        /* dithered conversion */
        av_dlog(ac->avr, "%d samples - audio_convert: %s to %s (dithered)\n",
                len, av_get_sample_fmt_name(ac->in_fmt),
                av_get_sample_fmt_name(ac->out_fmt));

        return ff_convert_dither(ac->dc, out, in);
    }

    /* determine whether to use the optimized function based on pointer and
       samples alignment in both the input and output */
    if (ac->has_optimized_func) {
        int ptr_align     = FFMIN(in->ptr_align,     out->ptr_align);
        int samples_align = FFMIN(in->samples_align, out->samples_align);
        int aligned_len   = FFALIGN(len, ac->samples_align);
        if (!(ptr_align % ac->ptr_align) && samples_align >= aligned_len) {
            len = aligned_len;
            use_generic = 0;
        }
    }
    av_dlog(ac->avr, "%d samples - audio_convert: %s to %s (%s)\n", len,
            av_get_sample_fmt_name(ac->in_fmt),
            av_get_sample_fmt_name(ac->out_fmt),
            use_generic ? ac->func_descr_generic : ac->func_descr);

    if (ac->apply_map) {
        ChannelMapInfo *map = &ac->avr->ch_map_info;

        if (!av_sample_fmt_is_planar(ac->out_fmt)) {
            av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n");
            return AVERROR(EINVAL);
        }

        if (map->do_remap) {
            if (av_sample_fmt_is_planar(ac->in_fmt)) {
                conv_func_flat *convert = use_generic ? ac->conv_flat_generic :
                                                        ac->conv_flat;

                for (p = 0; p < ac->planes; p++)
                    if (map->channel_map[p] >= 0)
                        convert(out->data[p], in->data[map->channel_map[p]], len);
            } else {
                uint8_t *data[AVRESAMPLE_MAX_CHANNELS];
                conv_func_deinterleave *convert = use_generic ?
                                                  ac->conv_deinterleave_generic :
                                                  ac->conv_deinterleave;

                for (p = 0; p < ac->channels; p++)
                    data[map->input_map[p]] = out->data[p];

                convert(data, in->data[0], len, ac->channels);
            }
        }
        if (map->do_copy || map->do_zero) {
            for (p = 0; p < ac->planes; p++) {
                if (map->channel_copy[p])
                    memcpy(out->data[p], out->data[map->channel_copy[p]],
                           len * out->stride);
                else if (map->channel_zero[p])
                    av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt);
            }
        }
    } else {
        switch (ac->func_type) {
        case CONV_FUNC_TYPE_FLAT: {
            if (!in->is_planar)
                len *= in->channels;
            if (use_generic) {
                for (p = 0; p < ac->planes; p++)
                    ac->conv_flat_generic(out->data[p], in->data[p], len);
            } else {
                for (p = 0; p < ac->planes; p++)
                    ac->conv_flat(out->data[p], in->data[p], len);
            }
            break;
        }
        case CONV_FUNC_TYPE_INTERLEAVE:
            if (use_generic)
                ac->conv_interleave_generic(out->data[0], in->data, len,
                                            ac->channels);
            else
                ac->conv_interleave(out->data[0], in->data, len, ac->channels);
            break;
        case CONV_FUNC_TYPE_DEINTERLEAVE:
            if (use_generic)
                ac->conv_deinterleave_generic(out->data, in->data[0], len,
                                              ac->channels);
            else
                ac->conv_deinterleave(out->data, in->data[0], len,
                                      ac->channels);
            break;
        }
    }

    out->nb_samples = in->nb_samples;
    return 0;
}
Exemple #2
0
int ff_audio_mix(AudioMix *am, AudioData *src)
{
    int use_generic = 1;
    int len = src->nb_samples;
    int i, j;

    /* determine whether to use the optimized function based on pointer and
       samples alignment in both the input and output */
    if (am->has_optimized_func) {
        int aligned_len = FFALIGN(len, am->samples_align);
        if (!(src->ptr_align % am->ptr_align) &&
            src->samples_align >= aligned_len) {
            len = aligned_len;
            use_generic = 0;
        }
    }
    av_dlog(am->avr, "audio_mix: %d samples - %d to %d channels (%s)\n",
            src->nb_samples, am->in_channels, am->out_channels,
            use_generic ? am->func_descr_generic : am->func_descr);

    if (am->in_matrix_channels && am->out_matrix_channels) {
        uint8_t **data;
        uint8_t *data0[AVRESAMPLE_MAX_CHANNELS] = { NULL };

        if (am->out_matrix_channels < am->out_channels ||
             am->in_matrix_channels <  am->in_channels) {
            for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) {
                if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i])
                    continue;
                data0[j++] = src->data[i];
            }
            data = data0;
        } else {
            data = src->data;
        }

        if (use_generic)
            am->mix_generic(data, am->matrix, len, am->out_matrix_channels,
                            am->in_matrix_channels);
        else
            am->mix(data, am->matrix, len, am->out_matrix_channels,
                    am->in_matrix_channels);
    }

    if (am->out_matrix_channels < am->out_channels) {
        for (i = 0; i < am->out_channels; i++)
            if (am->output_zero[i])
                av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt);
    }

    ff_audio_data_set_channels(src, am->out_channels);

    /* clip protection is only enabled when the internal sample format is fltp, so we don't need to check here */
    if (am->clip_protection) {
        for(i = 0; i < src->nb_samples; i++) {
            for (j = 0; j < src->channels; j++) {
                const float sample = fabs(((float **)src->data)[j][i]);
                if (sample > am->clip_max) {
                    am->clip_max = sample;
                    av_log(am->avr, AV_LOG_INFO, "Clipping protection at %.3f\n", sample);
                }
                if (am->clip_max > 1.0f)
                    ((float **)src->data)[j][i] /= am->clip_max;
            }
        }
    }

    return 0;
}
Exemple #3
0
static int return_audio_frame(AVFilterContext *ctx)
{
    AVFilterLink *link = ctx->outputs[0];
    FifoContext *s = ctx->priv;
    AVFilterBufferRef *head = s->root.next->buf;
    AVFilterBufferRef *buf_out;
    int ret;

    if (!s->buf_out &&
        head->audio->nb_samples >= link->request_samples &&
        calc_ptr_alignment(head) >= 32) {
        if (head->audio->nb_samples == link->request_samples) {
            buf_out = head;
            queue_pop(s);
        } else {
            buf_out = avfilter_ref_buffer(head, AV_PERM_READ);
            if (!buf_out)
                return AVERROR(ENOMEM);

            buf_out->audio->nb_samples = link->request_samples;
            buffer_offset(link, head, link->request_samples);
        }
    } else {
        int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);

        if (!s->buf_out) {
            s->buf_out = ff_get_audio_buffer(link, AV_PERM_WRITE,
                                             link->request_samples);
            if (!s->buf_out)
                return AVERROR(ENOMEM);

            s->buf_out->audio->nb_samples = 0;
            s->buf_out->pts               = head->pts;
            s->allocated_samples          = link->request_samples;
        } else if (link->request_samples != s->allocated_samples) {
            av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
                   "buffer was returned.\n");
            return AVERROR(EINVAL);
        }

        while (s->buf_out->audio->nb_samples < s->allocated_samples) {
            int len = FFMIN(s->allocated_samples - s->buf_out->audio->nb_samples,
                            head->audio->nb_samples);

            av_samples_copy(s->buf_out->extended_data, head->extended_data,
                            s->buf_out->audio->nb_samples, 0, len, nb_channels,
                            link->format);
            s->buf_out->audio->nb_samples += len;

            if (len == head->audio->nb_samples) {
                avfilter_unref_buffer(head);
                queue_pop(s);

                if (!s->root.next &&
                    (ret = ff_request_frame(ctx->inputs[0])) < 0) {
                    if (ret == AVERROR_EOF) {
                        av_samples_set_silence(s->buf_out->extended_data,
                                               s->buf_out->audio->nb_samples,
                                               s->allocated_samples -
                                               s->buf_out->audio->nb_samples,
                                               nb_channels, link->format);
                        s->buf_out->audio->nb_samples = s->allocated_samples;
                        break;
                    }
                    return ret;
                }
                head = s->root.next->buf;
            } else {
                buffer_offset(link, head, len);
            }
        }
        buf_out = s->buf_out;
        s->buf_out = NULL;
    }
    return ff_filter_samples(link, buf_out);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
{
    AVFilterContext  *ctx = inlink->dst;
    ASyncContext       *s = ctx->priv;
    AVFilterLink *outlink = ctx->outputs[0];
    int nb_channels = av_get_channel_layout_nb_channels(buf->channel_layout);
    int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts :
                  av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
    int out_size, ret;
    int64_t delta;
    int64_t new_pts;

    /* buffer data until we get the next timestamp */
    if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) {
        if (pts != AV_NOPTS_VALUE) {
            s->pts = pts - get_delay(s);
        }
        return write_to_fifo(s, buf);
    }

    if (s->first_pts != AV_NOPTS_VALUE) {
        handle_trimming(ctx);
        if (!avresample_available(s->avr))
            return write_to_fifo(s, buf);
    }

    /* when we have two timestamps, compute how many samples would we have
     * to add/remove to get proper sync between data and timestamps */
    delta    = pts - s->pts - get_delay(s);
    out_size = avresample_available(s->avr);

    if (labs(delta) > s->min_delta ||
        (s->first_frame && delta && s->first_pts != AV_NOPTS_VALUE)) {
        av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta);
        out_size = av_clipl_int32((int64_t)out_size + delta);
    } else {
        if (s->resample) {
            // adjust the compensation if delta is non-zero
            int delay = get_delay(s);
            int comp = s->comp + av_clip(delta * inlink->sample_rate / delay,
                                         -s->max_comp, s->max_comp);
            if (comp != s->comp) {
                av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp);
                if (avresample_set_compensation(s->avr, comp, inlink->sample_rate) == 0) {
                    s->comp = comp;
                }
            }
        }
        // adjust PTS to avoid monotonicity errors with input PTS jitter
        pts -= delta;
        delta = 0;
    }

    if (out_size > 0) {
        AVFrame *buf_out = ff_get_audio_buffer(outlink, out_size);
        if (!buf_out) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }

        if (s->first_frame && delta > 0) {
            int ch;

            av_samples_set_silence(buf_out->extended_data, 0, delta,
                                   nb_channels, buf->format);

            for (ch = 0; ch < nb_channels; ch++)
                buf_out->extended_data[ch] += delta;

            avresample_read(s->avr, buf_out->extended_data, out_size);

            for (ch = 0; ch < nb_channels; ch++)
                buf_out->extended_data[ch] -= delta;
        } else {
            avresample_read(s->avr, buf_out->extended_data, out_size);

            if (delta > 0) {
                av_samples_set_silence(buf_out->extended_data, out_size - delta,
                                       delta, nb_channels, buf->format);
            }
        }
        buf_out->pts = s->pts;
        ret = ff_filter_frame(outlink, buf_out);
        if (ret < 0)
            goto fail;
        s->got_output = 1;
    } else if (avresample_available(s->avr)) {
        av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
               "whole buffer.\n");
    }

    /* drain any remaining buffered data */
    avresample_read(s->avr, NULL, avresample_available(s->avr));

    new_pts = pts - avresample_get_delay(s->avr);
    /* check for s->pts monotonicity */
    if (new_pts > s->pts) {
        s->pts = new_pts;
        ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
                                 buf->linesize[0], buf->nb_samples);
    } else {
        av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
               "whole buffer.\n");
        ret = 0;
    }

    s->first_frame = 0;
fail:
    av_frame_free(&buf);

    return ret;
}
Exemple #5
0
static int return_audio_frame(AVFilterContext *ctx)
{
    AVFilterLink *link = ctx->outputs[0];
    FifoContext *s = ctx->priv;
    AVFrame *head = s->root.next ? s->root.next->frame : NULL;
    AVFrame *out;
    int ret;

    /* if head is NULL then we're flushing the remaining samples in out */
    if (!head && !s->out)
        return AVERROR_EOF;

    if (!s->out &&
        head->nb_samples >= link->request_samples &&
        calc_ptr_alignment(head) >= 32) {
        if (head->nb_samples == link->request_samples) {
            out = head;
            queue_pop(s);
        } else {
            out = av_frame_clone(head);
            if (!out)
                return AVERROR(ENOMEM);

            out->nb_samples = link->request_samples;
            buffer_offset(link, head, link->request_samples);
        }
    } else {
        int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);

        if (!s->out) {
            s->out = ff_get_audio_buffer(link, link->request_samples);
            if (!s->out)
                return AVERROR(ENOMEM);

            s->out->nb_samples = 0;
            s->out->pts                   = head->pts;
            s->allocated_samples          = link->request_samples;
        } else if (link->request_samples != s->allocated_samples) {
            av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
                   "buffer was returned.\n");
            return AVERROR(EINVAL);
        }

        while (s->out->nb_samples < s->allocated_samples) {
            int len;

            if (!s->root.next) {
                ret = ff_request_frame(ctx->inputs[0]);
                if (ret == AVERROR_EOF) {
                    av_samples_set_silence(s->out->extended_data,
                                           s->out->nb_samples,
                                           s->allocated_samples -
                                           s->out->nb_samples,
                                           nb_channels, link->format);
                    s->out->nb_samples = s->allocated_samples;
                    break;
                } else if (ret < 0)
                    return ret;
                av_assert0(s->root.next); // If ff_request_frame() succeeded then we should have a frame
            }
            head = s->root.next->frame;

            len = FFMIN(s->allocated_samples - s->out->nb_samples,
                        head->nb_samples);

            av_samples_copy(s->out->extended_data, head->extended_data,
                            s->out->nb_samples, 0, len, nb_channels,
                            link->format);
            s->out->nb_samples += len;

            if (len == head->nb_samples) {
                av_frame_free(&head);
                queue_pop(s);
            } else {
                buffer_offset(link, head, len);
            }
        }
        out = s->out;
        s->out = NULL;
    }
    return ff_filter_frame(link, out);
}