示例#1
0
/** @internal @This checks and parses a "#EXT-X-BYTERANGE" tag.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param line the trailing characters of the line
 * @return an error code
 */
static int upipe_m3u_reader_process_byte_range(struct upipe *upipe,
                                               struct uref *flow_def,
                                               const char *line)
{
    const char *def;
    struct uref *item;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def));
    if (strcmp(def, M3U_FLOW_DEF) && strcmp(def, PLAYLIST_FLOW_DEF))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, PLAYLIST_FLOW_DEF));
    UBASE_RETURN(upipe_m3u_reader_get_item(upipe, flow_def, &item));

    char *endptr = NULL;
    unsigned long long byte_range_len = strtoull(line, &endptr, 10);
    if (endptr == line || (*endptr != '\0' && *endptr != '@')) {
        upipe_warn_va(upipe, "invalid byte range %s", line);
        return UBASE_ERR_INVALID;
    }

    upipe_verbose_va(upipe, "byte range length: %"PRIu64, byte_range_len);
    if (*endptr == '@') {
        line = endptr + 1;
        unsigned long long byte_range_off = strtoull(line, &endptr, 10);
        if (endptr == line || *endptr != '\0') {
            upipe_warn_va(upipe, "invalid byte range %s", line);
            return UBASE_ERR_INVALID;
        }

        upipe_verbose_va(upipe, "byte range offset: %"PRIu64, byte_range_off);
        UBASE_RETURN(uref_m3u_playlist_set_byte_range_off(
                item, byte_range_off));
    }

    return uref_m3u_playlist_set_byte_range_len(item, byte_range_len);
}
/** @internal @This interpolates the PCRs for packets without a PCR.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_ts_pcr_interpolator_input(struct upipe *upipe, struct uref *uref,
                                  struct upump **upump_p)
{
    struct upipe_ts_pcr_interpolator *upipe_ts_pcr_interpolator = upipe_ts_pcr_interpolator_from_upipe(upipe);
    bool discontinuity = ubase_check(uref_flow_get_discontinuity(uref));
    if (discontinuity) {
        upipe_ts_pcr_interpolator->last_pcr = 0;
        upipe_ts_pcr_interpolator->packets = 0;
        upipe_ts_pcr_interpolator->pcr_packets = 0;
        upipe_ts_pcr_interpolator->pcr_delta = 0;
        upipe_ts_pcr_interpolator->discontinuity = true;
        upipe_notice_va(upipe, "Clearing state");
    }

    upipe_ts_pcr_interpolator->packets++;

    uint64_t pcr_prog = 0;
    uref_clock_get_cr_prog(uref, &pcr_prog);

    if (pcr_prog) {
        uint64_t delta = pcr_prog - upipe_ts_pcr_interpolator->last_pcr;
        upipe_ts_pcr_interpolator->last_pcr = pcr_prog;

        upipe_verbose_va(upipe,
                "pcr_prog %"PRId64" offset %"PRId64" stored offset %"PRIu64" bitrate %"PRId64" bps",
                pcr_prog, delta,
                upipe_ts_pcr_interpolator->pcr_delta,
                INT64_C(27000000) * upipe_ts_pcr_interpolator->packets * 188 * 8 / delta);

        if (upipe_ts_pcr_interpolator->pcr_delta)
            upipe_ts_pcr_interpolator->pcr_packets = upipe_ts_pcr_interpolator->packets;

        upipe_ts_pcr_interpolator->pcr_delta = delta;
        upipe_ts_pcr_interpolator->packets = 0;
    } else if (upipe_ts_pcr_interpolator->pcr_packets) {
        uint64_t offset = upipe_ts_pcr_interpolator->pcr_delta *
                    upipe_ts_pcr_interpolator->packets / upipe_ts_pcr_interpolator->pcr_packets;
        uint64_t prog = upipe_ts_pcr_interpolator->last_pcr + offset;
        uref_clock_set_date_prog(uref, prog, UREF_DATE_CR);
        upipe_throw_clock_ts(upipe, uref);
    }

    if (!upipe_ts_pcr_interpolator->pcr_packets) {
        uref_free(uref);
        return;
    }

    if (upipe_ts_pcr_interpolator->discontinuity) {
        uref_flow_set_discontinuity(uref);
        upipe_ts_pcr_interpolator->discontinuity = false;
    }
    upipe_ts_pcr_interpolator_output(upipe, uref, upump_p);
}
示例#3
0
/** @internal @This checks an URI.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param uri the uri
 * @return an error code
 */
static int upipe_m3u_reader_process_uri(struct upipe *upipe,
                                        struct uref *flow_def,
                                        const char *uri)
{
    struct upipe_m3u_reader *upipe_m3u_reader =
        upipe_m3u_reader_from_upipe(upipe);

    upipe_verbose_va(upipe, "uri %s", uri);
    UBASE_RETURN(uref_flow_match_def(flow_def, M3U_FLOW_DEF));
    struct uref *item;
    UBASE_RETURN(upipe_m3u_reader_get_item(upipe, flow_def, &item));
    UBASE_RETURN(uref_m3u_set_uri(item, uri));
    if (upipe_m3u_reader->key)
        UBASE_RETURN(uref_m3u_playlist_key_copy(item, upipe_m3u_reader->key));
    upipe_m3u_reader->item = NULL;
    ulist_add(&upipe_m3u_reader->items, uref_to_uchain(item));
    return UBASE_ERR_NONE;
}
示例#4
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);
}
示例#5
0
/** @internal @This checks and parses a "#EXTINF" tag.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param line the trailing characters of the line
 * @return an error code
 */
static int upipe_m3u_reader_process_extinf(struct upipe *upipe,
                                           struct uref *flow_def,
                                           const char *line)
{
    const char *def;
    struct uref *item;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def));
    if (strcmp(def, M3U_FLOW_DEF) && strcmp(def, PLAYLIST_FLOW_DEF))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, PLAYLIST_FLOW_DEF));
    UBASE_RETURN(upipe_m3u_reader_get_item(upipe, flow_def, &item));

    const char *endptr;
    uint64_t duration;
    UBASE_RETURN(duration_to_uclock(line, &endptr, &duration));
    if (line == endptr || *endptr != ',') {
        upipe_err_va(upipe, "invalid segment duration `%s'", line);
        return UBASE_ERR_INVALID;
    }
    upipe_verbose_va(upipe, "segment duration: %"PRIu64, duration);
    return uref_m3u_playlist_set_seq_duration(item, duration);
}
示例#6
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);
}
示例#7
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 * @return always true
 */
static bool upipe_filter_blend_handle(struct upipe *upipe, struct uref *uref,
                                      struct upump **upump_p)
{
    struct upipe_filter_blend *upipe_filter_blend = upipe_filter_blend_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        upipe_filter_blend_store_flow_def(upipe, NULL);
        upipe_filter_blend_require_ubuf_mgr(upipe, uref);
        return true;
    }

    if (upipe_filter_blend->flow_def == NULL)
        return false;

    const uint8_t *in;
    uint8_t *out;
    uint8_t hsub, vsub, macropixel_size;
    size_t stride_in = 0, stride_out = 0, width, height;
    const char *chroma = NULL;
    struct ubuf *ubuf_deint = NULL;

    // Now process frames
    uref_pic_size(uref, &width, &height, NULL);
    upipe_verbose_va(upipe, "received pic (%zux%zu)", width, height);

    assert(upipe_filter_blend->ubuf_mgr);
    ubuf_deint = ubuf_pic_alloc(upipe_filter_blend->ubuf_mgr, width, height);
    if (unlikely(!ubuf_deint)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        goto error;
    }

    // Iterate planes
    while (ubase_check(uref_pic_plane_iterate(uref, &chroma)) && chroma) {
        // map all
        if (unlikely(!ubase_check(uref_pic_plane_size(uref, chroma, &stride_in,
                                                &hsub, &vsub, &macropixel_size)))) {
            upipe_err_va(upipe, "Could not read origin chroma %s", chroma);
            goto error;
        }
        if (unlikely(!ubase_check(ubuf_pic_plane_size(ubuf_deint, chroma, &stride_out,
                                                  NULL, NULL, NULL)))) {
            upipe_err_va(upipe, "Could not read dest chroma %s", chroma);
            goto error;
        }
        uref_pic_plane_read(uref, chroma, 0, 0, -1, -1, &in);
        ubuf_pic_plane_write(ubuf_deint, chroma, 0, 0, -1, -1, &out);

        // process plane
        upipe_filter_blend_plane(in, out, stride_in, stride_out, (size_t) height/vsub, macropixel_size);

        // unmap all
        uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1);
        ubuf_pic_plane_unmap(ubuf_deint, chroma, 0, 0, -1, -1);
    }

    // Attach new ubuf and output frame
    uref_attach_ubuf(uref, ubuf_deint);
    uref_pic_set_progressive(uref);
    uref_pic_delete_tff(uref);

    upipe_filter_blend_output(upipe, uref, upump_p);
    return true;

error:
    uref_free(uref);
    if (ubuf_deint) {
        ubuf_free(ubuf_deint);
    }
    return true;
}