예제 #1
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_filter_ebur128_input(struct upipe *upipe, struct uref *uref,
                                       struct upump **upump_p)
{
    struct upipe_filter_ebur128 *upipe_filter_ebur128 =
                                 upipe_filter_ebur128_from_upipe(upipe);
    double loud = 0, lra = 0, global = 0;
    size_t samples;
    if (unlikely(!ubase_check(uref_sound_size(uref, &samples, NULL)))) {
        upipe_warn(upipe, "invalid sound buffer");
        uref_free(uref);
        return;
    }
    const char *channel = NULL;
    const int16_t *buf = NULL;
    if (ubase_check(uref_sound_plane_iterate(uref, &channel)) && channel) {
        if (unlikely(!ubase_check(uref_sound_plane_read_int16_t(uref,
                channel, 0, -1, &buf)))) {
            upipe_warn(upipe, "error mapping sound buffer");
            uref_free(uref);
            return;
        }

        if (unlikely((uintptr_t)buf & 1)) {
            upipe_warn(upipe, "unaligned buffer");
        }
        ebur128_add_frames_short(upipe_filter_ebur128->st, buf, samples);
        uref_sound_plane_unmap(uref, channel, 0, -1);
    }
    ebur128_loudness_momentary(upipe_filter_ebur128->st, &loud);
    ebur128_loudness_range(upipe_filter_ebur128->st, &lra);
    ebur128_loudness_global(upipe_filter_ebur128->st, &global);

    uref_ebur128_set_momentary(uref, loud);
    uref_ebur128_set_lra(uref, lra);
    uref_ebur128_set_global(uref, global);

    upipe_verbose_va(upipe, "loud %f lra %f global %f", loud, lra, global);

    upipe_filter_ebur128_output(upipe, uref, upump_p);
}
예제 #2
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_filter_ebur128_input(struct upipe *upipe, struct uref *uref,
                                       struct upump **upump_p)
{
    struct upipe_filter_ebur128 *upipe_filter_ebur128 =
                                 upipe_filter_ebur128_from_upipe(upipe);
    double loud = 0, lra = 0, global = 0;

    if (unlikely(upipe_filter_ebur128->output_flow == NULL)) {
        upipe_err_va(upipe, "invalid input");
        uref_free(uref);
        return;
    }

    size_t samples;
    uint8_t sample_size;
    if (unlikely(!ubase_check(uref_sound_size(uref, &samples, &sample_size)))) {
        upipe_warn(upipe, "invalid sound buffer");
        uref_free(uref);
        return;
    }

    void *buf = NULL;
    const char *channel = NULL;
    if (upipe_filter_ebur128->planes == 1) {
        if (ubase_check(uref_sound_plane_iterate(uref, &channel)) && channel) {
            if (unlikely(!ubase_check(uref_sound_plane_read_void(uref,
                    channel, 0, -1, (const void **)&buf)))) {
                upipe_warn(upipe, "error mapping sound buffer");
                uref_free(uref);
                return;
            }
        }

    } else {
        buf = malloc(sample_size * upipe_filter_ebur128->channels * samples);
        if (buf == NULL) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(uref);
            return;
        }
        if (!ubase_check(uref_sound_interleave(uref, (uint8_t *)buf, 0,
                                               samples, sample_size,
                                               upipe_filter_ebur128->planes))) {
            upipe_warn(upipe, "error mapping sound buffer");
            uref_free(uref);
            return;
        }
    }

    if (unlikely((uintptr_t)buf & 1))
        upipe_warn(upipe, "unaligned buffer");

    switch (upipe_filter_ebur128->fmt) {
        case UPIPE_FILTER_EBUR128_SHORT:
            ebur128_add_frames_short(upipe_filter_ebur128->st, (short *)buf,
                                     samples);
            break;

        case UPIPE_FILTER_EBUR128_INT:
            ebur128_add_frames_int(upipe_filter_ebur128->st, (int *)buf,
                                   samples);
            break;

        case UPIPE_FILTER_EBUR128_FLOAT:
            ebur128_add_frames_float(upipe_filter_ebur128->st, (float *)buf,
                                     samples);
            break;

        case UPIPE_FILTER_EBUR128_DOUBLE:
            ebur128_add_frames_double(upipe_filter_ebur128->st, (double *)buf,
                                      samples);
            break;

        default:
            upipe_warn_va(upipe, "unknown sample format %d",
                          upipe_filter_ebur128->fmt);
            break;
    }

    if (upipe_filter_ebur128->planes == 1)
        uref_sound_plane_unmap(uref, channel, 0, -1);
    else
        free(buf);

    ebur128_loudness_momentary(upipe_filter_ebur128->st, &loud);
    ebur128_loudness_range(upipe_filter_ebur128->st, &lra);
    ebur128_loudness_global(upipe_filter_ebur128->st, &global);

    uref_ebur128_set_momentary(uref, loud);
    uref_ebur128_set_lra(uref, lra);
    uref_ebur128_set_global(uref, global);

    upipe_verbose_va(upipe, "loud %f lra %f global %f", loud, lra, global);

    upipe_filter_ebur128_output(upipe, uref, upump_p);
}
예제 #3
0
/** @internal @This handles data from sound allocator.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_tblk_handle_sound(struct upipe *upipe, struct uref *uref,
                                    struct upump **upump_p)
{
    struct upipe_tblk *upipe_tblk = upipe_tblk_from_upipe(upipe);

    /* Always operate on the first channel plane. */
    const char *channel = NULL;
    if (unlikely(uref->ubuf == NULL ||
                 !ubase_check(ubuf_sound_plane_iterate(uref->ubuf, &channel)) ||
                 channel == NULL)) {
        uref_free(uref);
        upipe_throw_error(upipe, UBASE_ERR_INVALID);
        return;
    }

    /* First try the ubuf_mem_shared method. */
    struct ubuf *ubuf = ubuf_block_mem_alloc_from_sound(upipe_tblk->ubuf_mgr,
                                                        uref->ubuf, channel);
    if (unlikely(ubuf == NULL)) {
        /* We have to memcpy the thing. */
        size_t samples;
        uint8_t sample_size;
        if (unlikely(!ubase_check(uref_sound_size(uref, &samples,
                                                  &sample_size)))) {
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_INVALID);
            return;
        }

        size_t size = samples * sample_size;
        ubuf = ubuf_block_alloc(upipe_tblk->ubuf_mgr, size);
        if (unlikely(ubuf == NULL)) {
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        const uint8_t *r;
        if (unlikely(!ubase_check(uref_sound_plane_read_uint8_t(uref, channel,
                                                                0, -1, &r)))) {
            ubuf_free(ubuf);
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        uint8_t *w;
        int end = -1;
        if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &end, &w)))) {
            uref_sound_plane_unmap(uref, channel, 0, -1);
            ubuf_free(ubuf);
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        memcpy(w, r, size);
        ubuf_block_unmap(ubuf, 0);
        uref_sound_plane_unmap(uref, channel, 0, -1);
    }

    uref_attach_ubuf(uref, ubuf);
    upipe_tblk_output(upipe, uref, upump_p);
}
예제 #4
0
/** @internal @This is called back to fill NaCl audio buffer.
 * Please note that this function runs in a different thread.
 *
 * @param sample_buffer buffer to fill
 * @param buffer_size size of the buffer in octets
 * @param latency how long before the audio data is to be presented
 * @param user_data opaque pointing to the pipe
 */
static void upipe_nacl_audio_worker(void *sample_buffer, uint32_t buffer_size,
                                    PP_TimeDelta latency, void *user_data)
{
    struct upipe *upipe = (struct upipe *)user_data;
    struct upipe_nacl_audio *upipe_nacl_audio =
        upipe_nacl_audio_from_upipe(upipe);
    uint64_t next_pts = UINT64_MAX;

    if (likely(upipe_nacl_audio->uclock != NULL)) {
        /* This is slightly off. */
        next_pts = uclock_now(upipe_nacl_audio->uclock) +
                   (uint64_t)(latency * UCLOCK_FREQ);
    }

    uint32_t frames = buffer_size / 4;

    while (frames > 0) {
        if (upipe_nacl_audio->uref == NULL)
            upipe_nacl_audio->uref = uqueue_pop(&upipe_nacl_audio->uqueue,
                                                struct uref *);
        if (unlikely(upipe_nacl_audio->uref == NULL)) {
            upipe_dbg_va(upipe, "playing %u frames of silence (empty)", frames);
            memset(sample_buffer, 0, frames * 4);
            break;
        }

        struct uref *uref = upipe_nacl_audio->uref;
        if (next_pts != UINT64_MAX) {
            uint64_t uref_pts;
            if (unlikely(!ubase_check(uref_clock_get_pts_sys(uref,
                                &uref_pts)))) {
                upipe_nacl_audio->uref = NULL;
                uref_free(uref);
                upipe_warn(upipe, "non-dated uref received");
                continue;
            }

            int64_t tolerance = uref_pts - next_pts;
            if (tolerance > (int64_t)PTS_TOLERANCE) {
                uint32_t silence_frames =
                    tolerance * SAMPLE_RATE / UCLOCK_FREQ;
                if (silence_frames > frames)
                    silence_frames = frames;
                upipe_dbg_va(upipe, "playing %u frames of silence (wait)",
                             silence_frames);
                memset(sample_buffer, 0, silence_frames * 4);
                sample_buffer += silence_frames * 4;
                frames -= silence_frames;
                continue;
            } else if (-tolerance > (int64_t)PTS_TOLERANCE) {
                uint32_t dropped_frames =
                    (-tolerance) * SAMPLE_RATE / UCLOCK_FREQ;
                upipe_warn_va(upipe, "late buffer received, dropping %u frames",
                              dropped_frames);
                upipe_nacl_audio_consume(upipe, dropped_frames);
                continue;
            }
        }

        size_t size;
        const void *uref_buffer;
        if (unlikely(!ubase_check(uref_sound_size(uref, &size, NULL)) ||
                     !ubase_check(uref_sound_plane_read_void(uref, "lr", 0, -1,
                                                             &uref_buffer)))) {
            upipe_nacl_audio->uref = NULL;
            uref_free(uref);
            upipe_warn(upipe, "cannot read ubuf buffer");
            continue;
        }

        uint32_t copied_frames = size < frames ? size : frames;
        memcpy(sample_buffer, uref_buffer, copied_frames * 4);
        uref_sound_plane_unmap(uref, "lr", 0, -1);
        sample_buffer += copied_frames * 4;

        upipe_nacl_audio_consume(upipe, copied_frames);
        frames -= copied_frames;
    }
}