예제 #1
0
파일: af_volume.c 프로젝트: Aseeker/mpv
static int control(struct af_instance *af, int cmd, void *arg)
{
    struct priv *s = af->priv;

    switch (cmd) {
    case AF_CONTROL_REINIT: {
        struct mp_audio *in = arg;

        mp_audio_copy_config(af->data, in);
        mp_audio_force_interleaved_format(af->data);

        if (s->fast && af_fmt_from_planar(in->format) != AF_FORMAT_FLOAT) {
            mp_audio_set_format(af->data, AF_FORMAT_S16);
        } else {
            mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
        }
        if (af_fmt_is_planar(in->format))
            mp_audio_set_format(af->data, af_fmt_to_planar(af->data->format));
        return af_test_output(af, in);
    }
    case AF_CONTROL_SET_VOLUME:
        s->level = *(float *)arg;
        return AF_OK;
    case AF_CONTROL_GET_VOLUME:
        *(float *)arg = s->level;
        return AF_OK;
    }
    return AF_UNKNOWN;
}
예제 #2
0
static void do_reorder(struct mp_audio *mpa, int *reorder)
{
    if (af_fmt_is_planar(mpa->format)) {
        reorder_planes(mpa, reorder);
    } else {
        reorder_channels(mpa->planes[0], reorder, mpa->bps, mpa->nch, mpa->samples);
    }
}
예제 #3
0
파일: format.c 프로젝트: CrimsonVoid/mpv
int af_fmt_seconds_to_bytes(int format, float seconds, int channels, int samplerate)
{
    assert(!af_fmt_is_planar(format));
    int bps      = (af_fmt2bits(format) / 8);
    int framelen = channels * bps;
    int bytes    = seconds  * bps * samplerate;
    if (bytes % framelen)
        bytes += framelen - (bytes % framelen);
    return bytes;
}
예제 #4
0
파일: ao_lavc.c 프로젝트: Archer-sys/mpv
// must get exactly ac->aframesize amount of data
static void encode(struct ao *ao, double apts, void **data)
{
    struct priv *ac = ao->priv;
    struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
    double realapts = ac->aframecount * (double) ac->aframesize /
                      ao->samplerate;

    ac->aframecount++;

    if (data)
        ectx->audio_pts_offset = realapts - apts;

    if(data) {
        AVFrame *frame = av_frame_alloc();
        frame->format = af_to_avformat(ao->format);
        frame->nb_samples = ac->aframesize;

        size_t num_planes = af_fmt_is_planar(ao->format) ? ao->channels.num : 1;
        assert(num_planes <= AV_NUM_DATA_POINTERS);
        for (int n = 0; n < num_planes; n++)
            frame->extended_data[n] = data[n];

        frame->linesize[0] = frame->nb_samples * ao->sstride;

        if (ectx->options->rawts || ectx->options->copyts) {
            // real audio pts
            frame->pts = floor(apts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5);
        } else {
            // audio playback time
            frame->pts = floor(realapts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5);
        }

        int64_t frame_pts = av_rescale_q(frame->pts, ac->codec->time_base, ac->worst_time_base);
        if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) {
            // this indicates broken video
            // (video pts failing to increase fast enough to match audio)
            MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n",
                    (int)frame->pts, (int)ac->lastpts);
            frame_pts = ac->lastpts + 1;
            frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->codec->time_base);
        }
        ac->lastpts = frame_pts;

        frame->quality = ac->codec->global_quality;
        encode_audio_and_write(ao, frame);
        av_frame_free(&frame);
    }
    else
        encode_audio_and_write(ao, NULL);
}
예제 #5
0
static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
{
    struct af_resample *s = af->priv;
    struct mp_audio *in   = data;
    struct mp_audio *out  = af->data;

    out->samples = avresample_available(s->avrctx) +
        av_rescale_rnd(get_delay(s) + in->samples,
                       s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP);

    mp_audio_realloc_min(out, out->samples);

    af->delay = get_delay(s) / (double)s->ctx.in_rate;

#if !USE_SET_CHANNEL_MAPPING
    do_reorder(in, s->reorder_in);
#endif

    if (out->samples) {
        out->samples = avresample_convert(s->avrctx,
            (uint8_t **) out->planes, out->samples * out->sstride, out->samples,
            (uint8_t **) in->planes,  in->samples  * in->sstride,  in->samples);
        if (out->samples < 0)
            return NULL; // error
    }

    *data = *out;

#if USE_SET_CHANNEL_MAPPING
    if (needs_reorder(s->reorder_out, out->nch)) {
        if (af_fmt_is_planar(out->format)) {
            reorder_planes(data, s->reorder_out);
        } else {
            int out_size = out->samples * out->sstride;
            if (talloc_get_size(s->reorder_buffer) < out_size)
                s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
            data->planes[0] = s->reorder_buffer;
            int out_samples = avresample_convert(s->avrctx_out,
                    (uint8_t **) data->planes, out_size, out->samples,
                    (uint8_t **) out->planes, out_size, out->samples);
            assert(out_samples == data->samples);
        }
    }
#else
    do_reorder(data, s->reorder_out);
#endif

    return data;
}
예제 #6
0
파일: ao_lavc.c 프로젝트: Archer-sys/mpv
// this should round samples down to frame sizes
// return: number of samples played
static int play(struct ao *ao, void **data, int samples, int flags)
{
    struct priv *ac = ao->priv;
    struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
    int bufpos = 0;
    double nextpts;
    double outpts;
    int orig_samples = samples;

    pthread_mutex_lock(&ectx->lock);

    if (!encode_lavc_start(ectx)) {
        MP_WARN(ao, "not ready yet for encoding audio\n");
        pthread_mutex_unlock(&ectx->lock);
        return 0;
    }

    double pts = ectx->last_audio_in_pts;
    pts += ectx->samples_since_last_pts / (double)ao->samplerate;

    size_t num_planes = af_fmt_is_planar(ao->format) ? ao->channels.num : 1;

    void *tempdata = NULL;
    void *padded[MP_NUM_CHANNELS];

    if ((flags & AOPLAY_FINAL_CHUNK) && (samples % ac->aframesize)) {
       tempdata = talloc_new(NULL);
       size_t bytelen = samples * ao->sstride;
       size_t extralen = (ac->aframesize - 1) * ao->sstride;
       for (int n = 0; n < num_planes; n++) {
           padded[n] = talloc_size(tempdata, bytelen + extralen);
           memcpy(padded[n], data[n], bytelen);
           af_fill_silence((char *)padded[n] + bytelen, extralen, ao->format);
       }
       data = padded;
       samples = (bytelen + extralen) / ao->sstride;
    }

    if (pts == MP_NOPTS_VALUE) {
        MP_WARN(ao, "frame without pts, please report; synthesizing pts instead\n");
        // synthesize pts from previous expected next pts
        pts = ac->expected_next_pts;
    }

    if (ac->worst_time_base.den == 0) {
        //if (ac->codec->time_base.num / ac->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den)
        if (ac->codec->time_base.num * (double) ac->stream->time_base.den >=
                ac->stream->time_base.num * (double) ac->codec->time_base.den) {
            MP_VERBOSE(ao, "NOTE: using codec time base (%d/%d) for pts "
                       "adjustment; the stream base (%d/%d) is not worse.\n",
                       (int)ac->codec->time_base.num,
                       (int)ac->codec->time_base.den,
                       (int)ac->stream->time_base.num,
                       (int)ac->stream->time_base.den);
            ac->worst_time_base = ac->codec->time_base;
            ac->worst_time_base_is_stream = 0;
        } else {
            MP_WARN(ao, "NOTE: not using codec time base (%d/%d) for pts "
                    "adjustment; the stream base (%d/%d) is worse.\n",
                    (int)ac->codec->time_base.num,
                    (int)ac->codec->time_base.den,
                    (int)ac->stream->time_base.num,
                    (int)ac->stream->time_base.den);
            ac->worst_time_base = ac->stream->time_base;
            ac->worst_time_base_is_stream = 1;
        }

        // NOTE: we use the following "axiom" of av_rescale_q:
        // if time base A is worse than time base B, then
        //   av_rescale_q(av_rescale_q(x, A, B), B, A) == x
        // this can be proven as long as av_rescale_q rounds to nearest, which
        // it currently does

        // av_rescale_q(x, A, B) * B = "round x*A to nearest multiple of B"
        // and:
        //    av_rescale_q(av_rescale_q(x, A, B), B, A) * A
        // == "round av_rescale_q(x, A, B)*B to nearest multiple of A"
        // == "round 'round x*A to nearest multiple of B' to nearest multiple of A"
        //
        // assume this fails. Then there is a value of x*A, for which the
        // nearest multiple of B is outside the range [(x-0.5)*A, (x+0.5)*A[.
        // Absurd, as this range MUST contain at least one multiple of B.
    }

    // Fix and apply the discontinuity pts offset.
    if (!ectx->options->rawts && ectx->options->copyts) {
        // fix the discontinuity pts offset
        nextpts = pts;
        if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
            ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
        }
        else if (fabs(nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts) > 30) {
            MP_WARN(ao, "detected an unexpected discontinuity (pts jumped by "
                    "%f seconds)\n",
                    nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts);
            ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
        }

        outpts = pts + ectx->discontinuity_pts_offset;
    }
    else {
        outpts = pts;
    }

    // Shift pts by the pts offset first.
    outpts += encode_lavc_getoffset(ectx, ac->codec);

    while (samples - bufpos >= ac->aframesize) {
        void *start[MP_NUM_CHANNELS] = {0};
        for (int n = 0; n < num_planes; n++)
            start[n] = (char *)data[n] + bufpos * ao->sstride;
        encode(ao, outpts + bufpos / (double) ao->samplerate, start);
        bufpos += ac->aframesize;
    }

    // Calculate expected pts of next audio frame (input side).
    ac->expected_next_pts = pts + bufpos / (double) ao->samplerate;

    // Set next allowed input pts value (input side).
    if (!ectx->options->rawts && ectx->options->copyts) {
        nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset;
        if (nextpts > ectx->next_in_pts)
            ectx->next_in_pts = nextpts;
    }

    talloc_free(tempdata);

    int taken = FFMIN(bufpos, orig_samples);
    ectx->samples_since_last_pts += taken;

    pthread_mutex_unlock(&ectx->lock);

    if (flags & AOPLAY_FINAL_CHUNK) {
        if (bufpos < orig_samples) {
            MP_ERR(ao, "did not write enough data at the end\n");
        }
    } else {
        if (bufpos > orig_samples) {
            MP_ERR(ao, "audio buffer overflow (should never happen)\n");
        }
    }

    return taken;
}
예제 #7
0
int AudioController::reinitialize(mp_audio *in) {
	if (!in)
		return AF_ERROR;
	auto makeFormat = [] (const mp_audio *audio) {
		AudioFormat format;
		format.m_samplerate = audio->rate/1000.0; // kHz
		format.m_bitrate = audio->rate*audio->nch*audio->bps*8;
		format.m_bits = audio->bps*8;
		format.m_channels = ChannelLayoutInfo::description(ChannelLayoutMap::toLayout(audio->channels));
		format.m_type = af_fmt_to_str(audio->format);
		return format;
	};
	d->input = makeFormat(in);
	auto out = d->af->data;
	out->rate = in->rate;
	bool ret = true;
	if (!isSupported(in->format)) {
		ret = false;
		mp_audio_set_format(in, af_fmt_is_planar(in->format) ? AF_FORMAT_FLOATP : AF_FORMAT_FLOAT);
	}
	if (d->fmt_conv) {
		mp_audio_set_format(out, d->fmt_conv);
		d->fmt_conv = AF_FORMAT_UNKNOWN;
	} else
		mp_audio_set_format(out, in->format);
	d->chmap = in->channels;
	if (!mp_chmap_from_str(&d->chmap, bstr0(ChannelLayoutInfo::data(d->layout).constData())))
		_Error("Cannot find matched channel layout for '%%'", ChannelLayoutInfo::description(d->layout));
	mp_audio_set_channels(out, &d->chmap);
	if (d->outrate != 0)
		out->rate = d->outrate;
	if (!ret)
		return false;
	d->af->mul = (double)out->channels.num/in->channels.num;
	if (d->tempoScalerActivated)
		d->af->mul /= d->scale;
	if ((d->resample = out->rate != in->rate)) {
		d->af->mul *= (double)out->rate/in->rate;
		const auto nch = in->channels.num;/*mp_chmap_to_lavc_unchecked(&in->channels);*/
		const auto fmt = af_to_avformat(in->format);
		if (!d->swr)
			d->swr = swr_alloc();
		av_opt_set_int(d->swr,  "in_channel_count", nch, 0);
		av_opt_set_int(d->swr, "out_channel_count", nch, 0);
		av_opt_set_int(d->swr,  "in_sample_rate", in->rate, 0);
		av_opt_set_int(d->swr, "out_sample_rate", out->rate, 0);
		av_opt_set_sample_fmt(d->swr,  "in_sample_fmt", fmt, 0);
		av_opt_set_sample_fmt(d->swr, "out_sample_fmt", fmt, 0);
		swr_init(d->swr);
		if (!d->resampled)
			d->resampled = talloc_zero(nullptr, mp_audio);
		*d->resampled = *in;
		d->resampled->rate = out->rate;
		in = d->resampled;
	}
	d->output = makeFormat(out);
	const AudioDataFormat fmt_in(*in), fmt_out(*out);
	check(d->mixer, d->clip, fmt_in, fmt_out);
	d->mixer->setOutput(out);
	d->mixer->setChannelLayoutMap(d->map);
	d->dirty = 0xffffffff;
	return true;
}