Exemplo n.º 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);
}
Exemplo n.º 2
0
/** @internal @This sets the input flow definition.
 *
 * @param upipe description structure of the pipe
 * @param flow_def flow definition packet
 * @return an error code
 */
static int upipe_s337_encaps_set_flow_def(struct upipe *upipe,
                                          struct uref *flow_def)
{
    if (flow_def == NULL)
        return UBASE_ERR_INVALID;

    const char *def;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def))

    uint64_t rate;
    UBASE_RETURN(uref_sound_flow_get_rate(flow_def, &rate))

    if (ubase_ncmp(def, EXPECTED_FLOW_DEF))
        return UBASE_ERR_INVALID;

    struct uref *flow_def_dup = uref_dup(flow_def);
    if (flow_def_dup == NULL)
        return UBASE_ERR_ALLOC;

    uref_flow_set_def(flow_def_dup, "sound.s32.s337.a52.");
    uref_sound_flow_set_channels(flow_def_dup, 2);
    uref_sound_flow_set_sample_size(flow_def_dup, 2*4);

    if (!ubase_check(uref_sound_flow_add_plane(flow_def_dup, "lr")) ||
        !ubase_check(uref_sound_flow_set_rate(flow_def_dup, rate))) {
        uref_free(flow_def_dup);
        return UBASE_ERR_ALLOC;
    }

    upipe_s337_encaps_require_ubuf_mgr(upipe, flow_def_dup);
    return UBASE_ERR_NONE;
}
Exemplo n.º 3
0
/** @internal @This checks and parses a "#EXT-X-STREAM-INF" 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_ext_x_stream_inf(struct upipe *upipe,
                                             struct uref *flow_def,
                                             const char *line)
{
    if (!ubase_check(uref_flow_match_def(flow_def, M3U_FLOW_DEF)) &&
        !ubase_check(uref_flow_match_def(flow_def, MASTER_FLOW_DEF)))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, MASTER_FLOW_DEF));

    struct uref *item;
    UBASE_RETURN(upipe_m3u_reader_get_item(upipe, flow_def, &item));

    const char *iterator = line;
    struct ustring name, value;
    while (ubase_check(attribute_iterate(&iterator, &name, &value)) &&
           iterator != NULL) {
        char value_str[value.len + 1];
        int err = ustring_cpy(value, value_str, sizeof (value_str));
        if (unlikely(!ubase_check(err))) {
            upipe_err_va(upipe, "fail to copy ustring %.*s",
                         (int)value.len, value.at);
            continue;
        }

        if (!ustring_cmp_str(name, "BANDWIDTH")) {
            char *endptr;
            uint64_t bandwidth = strtoull(value_str, &endptr, 10);
            if (endptr == value_str)
                return UBASE_ERR_INVALID;
            err = uref_m3u_master_set_bandwidth(item, bandwidth);
            if (unlikely(!ubase_check(err)))
                upipe_err_va(upipe, "fail to set bandwidth to %s", value_str);
        }
        else if (!ustring_cmp_str(name, "CODECS")) {
            err = uref_m3u_master_set_codecs(item, value_str);
            if (unlikely(!ubase_check(err)))
                upipe_err_va(upipe, "fail to set codecs to %s", value_str);
        }
        else if (!ustring_cmp_str(name, "AUDIO")) {
            err = uref_m3u_master_set_audio(item, value_str);
            if (unlikely(!ubase_check(err)))
                upipe_err_va(upipe, "fail to set audio to %s", value_str);
        }
        else if (!ustring_cmp_str(name, "RESOLUTION")) {
            err = uref_m3u_master_set_resolution(item, value_str);
            if (unlikely(!ubase_check(err)))
                upipe_err_va(upipe, "fail to set resolution to %s", value_str);
        }
        else {
            upipe_warn_va(upipe, "ignoring attribute %.*s (%.*s)",
                          (int)name.len, name.at,
                          (int)value.len, value.at);
        }
    }

    return UBASE_ERR_NONE;
}
Exemplo n.º 4
0
/** @internal @This checks a "#EXT-X-ENDLIST" 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_ext_x_endlist(struct upipe *upipe,
                                          struct uref *flow_def,
                                          const char *line)
{
    const char *def;
    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));

    upipe_verbose(upipe, "endlist tag");
    return uref_m3u_playlist_flow_set_endlist(flow_def);
}
Exemplo n.º 5
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 * @return false if the input must be blocked
 */
static bool upipe_tblk_handle(struct upipe *upipe, struct uref *uref,
                              struct upump **upump_p)
{
    struct upipe_tblk *upipe_tblk = upipe_tblk_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        if (!ubase_ncmp(def, "pic.")) {
            upipe_tblk->input_alloc = UBUF_ALLOC_PICTURE;
            uref_pic_flow_clear_format(uref);
            uref_flow_set_def(uref, "block.");
        } else if (!ubase_ncmp(def, "sound.")) {
            upipe_tblk->input_alloc = UBUF_ALLOC_SOUND;
            uref_sound_flow_clear_format(uref);
            uref_flow_set_def(uref, "block.");
        } else
            upipe_tblk->input_alloc = UBUF_ALLOC_BLOCK;

        upipe_tblk_store_flow_def(upipe, NULL);
        upipe_tblk_require_ubuf_mgr(upipe, uref);
        return true;
    }

    if (upipe_tblk->flow_def == NULL)
        return false;
    assert(upipe_tblk->ubuf_mgr != NULL);

    switch (upipe_tblk->input_alloc) {
        case UBUF_ALLOC_PICTURE:
            upipe_tblk_handle_pic(upipe, uref, upump_p);
            break;
        case UBUF_ALLOC_SOUND:
            upipe_tblk_handle_sound(upipe, uref, upump_p);
            break;
        default:
            upipe_tblk_output(upipe, uref, upump_p);
            break;
    }
    return true;
}
Exemplo n.º 6
0
/** @internal @This provides a flow format suggestion.
 *
 * @param upipe description structure of the pipe
 * @param request description structure of the request
 * @return an error code
 */
static int upipe_filter_ebur128_provide_flow_format(struct upipe *upipe,
                                                    struct urequest *request)
{
    const char *def;
    UBASE_RETURN(uref_flow_get_def(request->uref, &def))
    struct uref *flow = uref_dup(request->uref);
    UBASE_ALLOC_RETURN(flow);

    if (!ubase_ncmp(def, "sound.u8."))
        UBASE_FATAL(upipe, uref_flow_set_def(flow, "sound.s16."));

    return urequest_provide_flow_format(request, flow);
}
Exemplo n.º 7
0
/** @internal @This provides a flow format suggestion.
 *
 * @param upipe description structure of the pipe
 * @param request description structure of the request
 * @return an error code
 */
static int upipe_nacl_audio_provide_flow_format(struct upipe *upipe,
                                                struct urequest *request)
{
    struct uref *flow_format = uref_dup(request->uref);
    UBASE_ALLOC_RETURN(flow_format);
    uref_sound_flow_clear_format(flow_format);
    uref_flow_set_def(flow_format, EXPECTED_FLOW_DEF);
    uref_sound_flow_set_channels(flow_format, 2);
    uref_sound_flow_set_sample_size(flow_format, 4);
    uref_sound_flow_set_planes(flow_format, 0);
    uref_sound_flow_add_plane(flow_format, "lr");
    uref_sound_flow_set_rate(flow_format, SAMPLE_RATE);
    return urequest_provide_flow_format(request, flow_format);
}
Exemplo n.º 8
0
/** @internal @This sets the input flow definition.
 *
 * @param upipe description structure of the pipe
 * @param flow_def flow definition packet
 * @return an error code
 */
static int upipe_ts_check_set_flow_def(struct upipe *upipe,
                                       struct uref *flow_def)
{
    if (flow_def == NULL)
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF))
    struct uref *flow_def_dup;
    if (unlikely((flow_def_dup = uref_dup(flow_def)) == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }
    struct upipe_ts_check *upipe_ts_check = upipe_ts_check_from_upipe(upipe);
    UBASE_RETURN(uref_block_flow_set_size(flow_def_dup,
                                          upipe_ts_check->output_size))
    UBASE_RETURN(uref_flow_set_def(flow_def_dup, OUTPUT_FLOW_DEF))
    upipe_ts_check_store_flow_def(upipe, flow_def_dup);
    return UBASE_ERR_NONE;
}
Exemplo n.º 9
0
static int upipe_rtp_opus_set_flow_def(struct upipe *upipe,
                                       struct uref *flow_def)
{
    if (flow_def == NULL)
        return UBASE_ERR_INVALID;
    //UBASE_RETURN(uref_flow_match_def(flow_def, "block.opus.sound."))

    struct uref *flow_def_dup = uref_dup(flow_def);
    if (unlikely(flow_def_dup == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }

    uref_flow_set_def(flow_def_dup, "block.opus.sound.");

    upipe_rtp_opus_store_flow_def(upipe, flow_def_dup);
    return UBASE_ERR_NONE;
}
Exemplo n.º 10
0
/** @internal @This checks a "#EXTM3U" 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_m3u(struct upipe *upipe,
                                        struct uref *flow_def,
                                        const char *line)
{
    while (isspace(*line))
        line++;

    if (strlen(line)) {
        upipe_err(upipe, "invalid EXTM3U tag");
        return UBASE_ERR_INVALID;
    }
    upipe_verbose(upipe, "found EXTM3U tag");

    const char *def;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def));
    if (strcmp(def, EXPECTED_FLOW_DEF))
        return UBASE_ERR_INVALID;
    return uref_flow_set_def(flow_def, M3U_FLOW_DEF);
}
Exemplo n.º 11
0
/** @internal @This checks and parses a "#EXT-X-MEDIA-SEQUENCE" 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_ext_x_media_sequence(struct upipe *upipe,
                                                 struct uref *flow_def,
                                                 const char *line)
{
    const char *def;
    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));

    char *endptr;
    uint64_t media_sequence = strtoull(line, &endptr, 10);
    if (endptr == line || strlen(endptr)) {
        upipe_warn_va(upipe, "invalid media sequence %s", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "media sequence %"PRIu64, media_sequence);
    return uref_m3u_playlist_flow_set_media_sequence(flow_def, media_sequence);
}
Exemplo n.º 12
0
/** @internal @This checks and parses a "#EXT-X-TARGETDURATION" 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_target_duration(struct upipe *upipe,
                                                    struct uref *flow_def,
                                                    const char *line)
{
    const char *def;
    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));

    const char *endptr;
    uint64_t duration;
    UBASE_RETURN(duration_to_uclock(line, &endptr, &duration));
    if (line == endptr || strlen(endptr)) {
        upipe_warn_va(upipe, "invalid target duration %s", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "target duration: %"PRIu64, duration);
    return uref_m3u_playlist_flow_set_target_duration(flow_def, duration);
}
Exemplo n.º 13
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump pump that generated the buffer
 */
static void upipe_skip_input(struct upipe *upipe, struct uref *uref,
                               struct upump *upump)
{
    struct upipe_skip *upipe_skip = upipe_skip_from_upipe(upipe);
    const char *def;

    if (unlikely(uref_flow_get_def(uref, &def))) {
        if (unlikely(ubase_ncmp(def, EXPECTED_FLOW))) {
            upipe_throw_flow_def_error(upipe, uref);
            uref_free(uref);
            return;
        }

        upipe_dbg_va(upipe, "flow definition %s", def);
        if (unlikely(!uref_flow_set_def(uref, "block.")))
            upipe_throw_aerror(upipe);
        upipe_skip_store_flow_def(upipe, uref);
        return;
    }

    if (unlikely(uref_flow_get_end(uref))) {
        uref_free(uref);
        upipe_throw_need_input(upipe);
        return;
    }

    if (unlikely(upipe_skip->flow_def == NULL)) {
        upipe_throw_flow_def_error(upipe, uref);
        uref_free(uref);
        return;
    }

    if (unlikely(uref->ubuf == NULL)) {
        uref_free(uref);
        return;
    }

    upipe_skip_input_block(upipe, uref, upump);
}
Exemplo n.º 14
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);
}
Exemplo n.º 15
0
/** @internal @This checks and parses a "#EXT-X-PLAYLIST-TYPE" 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_playlist_type(struct upipe *upipe,
                                                  struct uref *flow_def,
                                                  const char *line)
{
    const char *def;
    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));

    static const char *types[] = { "VOD", "EVENT" };
    const char *type = NULL;
    for (unsigned i = 0; !type && i < UBASE_ARRAY_SIZE(types); i++)
        if (!strcmp(line, types[i]))
            type = types[i];
    if (unlikely(type == NULL)) {
        upipe_warn_va(upipe, "invalid playlist type `%s'", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "playlist type %s", type);
    return uref_m3u_playlist_flow_set_type(flow_def, type);
}
Exemplo n.º 16
0
/** @internal @This provides a flow format suggestion.
 *
 * @param upipe description structure of the pipe
 * @param request description structure of the request
 * @return an error code
 */
static int upipe_filter_ebur128_provide_flow_format(struct upipe *upipe,
                                                    struct urequest *request)
{
    struct uref *flow = uref_dup(request->uref);
    UBASE_ALLOC_RETURN(flow);

    uint8_t planes;
    if (ubase_check(uref_sound_flow_get_planes(request->uref, &planes))
                                                         && planes != 1) {
        /* compute sample size */
        uint8_t sample_size = 0;
        uref_sound_flow_get_sample_size(request->uref, &sample_size);
        sample_size *= planes;

        /* construct packed channel name from planar names */
        char packed_channel[planes+1];
        uint8_t plane;
        for (plane=0; plane < planes; plane++) {
            const char *planar_channel = "";
            uref_sound_flow_get_channel(request->uref, &planar_channel, plane);
            packed_channel[plane] = *planar_channel;
        }
        packed_channel[planes] = '\0';

        /* set attributes */
        uref_sound_flow_clear_format(flow);
        UBASE_FATAL(upipe, uref_sound_flow_set_channels(flow, planes));
        UBASE_FATAL(upipe, uref_sound_flow_set_sample_size(flow, sample_size));
        UBASE_FATAL(upipe, uref_sound_flow_set_channel(flow,
                                                       packed_channel, 0));
        UBASE_FATAL(upipe, uref_sound_flow_set_planes(flow, 1));
    }

    UBASE_FATAL(upipe, uref_flow_set_def(flow, "sound.s16."));

    return urequest_provide_flow_format(request, flow);
}
Exemplo n.º 17
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 * @return false if the input must be blocked
 */
static bool upipe_speexdsp_handle(struct upipe *upipe, struct uref *uref,
                             struct upump **upump_p)
{
    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);

    struct urational drift_rate;
    if (!ubase_check(uref_clock_get_rate(uref, &drift_rate)))
        drift_rate = (struct urational){ 1, 1 };

    /* reinitialize resampler when drift rate changes */
    if (urational_cmp(&drift_rate, &upipe_speexdsp->drift_rate)) {
        upipe_speexdsp->drift_rate = drift_rate;
        spx_uint32_t ratio_num = drift_rate.den;
        spx_uint32_t ratio_den = drift_rate.num;
        spx_uint32_t in_rate = upipe_speexdsp->rate * ratio_num / ratio_den;
        spx_uint32_t out_rate = upipe_speexdsp->rate;
        int err = speex_resampler_set_rate_frac(upipe_speexdsp->ctx,
                ratio_num, ratio_den, in_rate, out_rate);
        if (err) {
            upipe_err_va(upipe, "Couldn't resample from %u to %u: %s",
                in_rate, out_rate, speex_resampler_strerror(err));
        } else {
            upipe_dbg_va(upipe, "Resampling from %u to %u",
                in_rate, out_rate);
        }
    }

    size_t size;
    if (!ubase_check(uref_sound_size(uref, &size, NULL /* sample_size */))) {
        uref_free(uref);
        return true;
    }

    struct ubuf *ubuf = ubuf_sound_alloc(upipe_speexdsp->ubuf_mgr, size + 10);
    if (!ubuf)
        return false;

    const void *in;
    uref_sound_read_void(uref, 0, -1, &in, 1);

    void *out;
    ubuf_sound_write_void(ubuf, 0, -1, &out, 1);

    spx_uint32_t in_len = size;         /* input size */
    spx_uint32_t out_len = size + 10;   /* available output size */

    int err;

    if (upipe_speexdsp->f32)
        err = speex_resampler_process_interleaved_float(upipe_speexdsp->ctx,
                in, &in_len, out, &out_len);
    else
        err = speex_resampler_process_interleaved_int(upipe_speexdsp->ctx,
                in, &in_len, out, &out_len);

    if (err) {
        upipe_err_va(upipe, "Could not resample: %s",
                speex_resampler_strerror(err));
    }

    uref_sound_unmap(uref, 0, -1, 1);
    ubuf_sound_unmap(ubuf, 0, -1, 1);

    if (err) {
        ubuf_free(ubuf);
    } else {
        ubuf_sound_resize(ubuf, 0, out_len);
        uref_attach_ubuf(uref, ubuf);
    }

    upipe_speexdsp_output(upipe, uref, upump_p);
    return true;
}

/** @internal @This receives incoming uref.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure describing the picture
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_speexdsp_input(struct upipe *upipe, struct uref *uref,
                            struct upump **upump_p)
{
    if (!upipe_speexdsp_check_input(upipe)) {
        upipe_speexdsp_hold_input(upipe, uref);
        upipe_speexdsp_block_input(upipe, upump_p);
    } else if (!upipe_speexdsp_handle(upipe, uref, upump_p)) {
        upipe_speexdsp_hold_input(upipe, uref);
        upipe_speexdsp_block_input(upipe, upump_p);
        /* Increment upipe refcount to avoid disappearing before all packets
         * have been sent. */
        upipe_use(upipe);
    }
}

/** @internal @This receives a provided ubuf manager.
 *
 * @param upipe description structure of the pipe
 * @param flow_format amended flow format
 * @return an error code
 */
static int upipe_speexdsp_check(struct upipe *upipe, struct uref *flow_format)
{
    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);
    if (flow_format != NULL)
        upipe_speexdsp_store_flow_def(upipe, flow_format);

    if (upipe_speexdsp->flow_def == NULL)
        return UBASE_ERR_NONE;

    bool was_buffered = !upipe_speexdsp_check_input(upipe);
    upipe_speexdsp_output_input(upipe);
    upipe_speexdsp_unblock_input(upipe);
    if (was_buffered && upipe_speexdsp_check_input(upipe)) {
        /* All packets have been output, release again the pipe that has been
         * used in @ref upipe_speexdsp_input. */
        upipe_release(upipe);
    }
    return UBASE_ERR_NONE;
}

/** @internal @This sets the input flow definition.
 *
 * @param upipe description structure of the pipe
 * @param flow_def flow definition packet
 * @return an error code
 */
static int upipe_speexdsp_set_flow_def(struct upipe *upipe, struct uref *flow_def)
{
    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);

    if (flow_def == NULL)
        return UBASE_ERR_INVALID;

    const char *def;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def))

    if (unlikely(ubase_ncmp(def, "sound.f32.") &&
                ubase_ncmp(def, "sound.s16.")))
        return UBASE_ERR_INVALID;

    uint8_t in_planes;
    if (unlikely(!ubase_check(uref_sound_flow_get_planes(flow_def,
                                                         &in_planes))))
        return UBASE_ERR_INVALID;

    if (in_planes != 1) {
        upipe_err(upipe, "only interleaved audio is supported");
        return UBASE_ERR_INVALID;
    }

    if (!ubase_check(uref_sound_flow_get_rate(flow_def,
                    &upipe_speexdsp->rate))) {
        upipe_err(upipe, "no sound rate defined");
        uref_dump(flow_def, upipe->uprobe);
        return UBASE_ERR_INVALID;
    }

    uint8_t channels;
    if (unlikely(!ubase_check(uref_sound_flow_get_channels(flow_def,
                        &channels))))
        return UBASE_ERR_INVALID;

    flow_def = uref_dup(flow_def);
    if (unlikely(flow_def == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }

    upipe_speexdsp_require_ubuf_mgr(upipe, flow_def);

    if (upipe_speexdsp->ctx)
        speex_resampler_destroy(upipe_speexdsp->ctx);

    upipe_speexdsp->f32 = !ubase_ncmp(def, "sound.f32.");

    int err;
    upipe_speexdsp->ctx = speex_resampler_init(channels,
                upipe_speexdsp->rate, upipe_speexdsp->rate,
                upipe_speexdsp->quality, &err);
    if (!upipe_speexdsp->ctx) {
        upipe_err_va(upipe, "Could not create resampler: %s",
                speex_resampler_strerror(err));
        return UBASE_ERR_INVALID;
    }

    return UBASE_ERR_NONE;
}

/** @internal @This provides a flow format suggestion.
 *
 * @param upipe description structure of the pipe
 * @param request description structure of the request
 * @return an error code
 */
static int upipe_speexdsp_provide_flow_format(struct upipe *upipe,
                                          struct urequest *request)
{
    const char *def;
    UBASE_RETURN(uref_flow_get_def(request->uref, &def))
    uint8_t channels;
    UBASE_RETURN(uref_sound_flow_get_channels(request->uref, &channels))
    uint8_t planes;
    UBASE_RETURN(uref_sound_flow_get_planes(request->uref, &planes))
    uint8_t sample_size;
    UBASE_RETURN(uref_sound_flow_get_sample_size(request->uref, &sample_size))

    struct uref *flow = uref_dup(request->uref);
    UBASE_ALLOC_RETURN(flow);

    uref_sound_flow_clear_format(flow);
    uref_sound_flow_set_planes(flow, 0);
    uref_sound_flow_set_channels(flow, channels);
    uref_sound_flow_add_plane(flow, "all");
    if (ubase_ncmp(def, "sound.s16.")) {
        uref_flow_set_def(flow, "sound.f32."); /* prefer f32 over s16 */
        uref_sound_flow_set_sample_size(flow, 4 * channels);
    } else {
        uref_flow_set_def(flow, def);
        uref_sound_flow_set_sample_size(flow, (planes > 1) ? sample_size :
                sample_size / channels);
    }

    return urequest_provide_flow_format(request, flow);
}

/** @internal @This processes control commands on a speexdsp pipe.
 *
 * @param upipe description structure of the pipe
 * @param command type of command to process
 * @param args arguments of the command
 * @return an error code
 */
static int upipe_speexdsp_control(struct upipe *upipe, int command, va_list args)
{
    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);

    switch (command) {
        /* generic commands */
        case UPIPE_REGISTER_REQUEST: {
            struct urequest *request = va_arg(args, struct urequest *);
            if (request->type == UREQUEST_FLOW_FORMAT)
                return upipe_speexdsp_provide_flow_format(upipe, request);
            if (request->type == UREQUEST_UBUF_MGR)
                return upipe_throw_provide_request(upipe, request);
            return upipe_speexdsp_alloc_output_proxy(upipe, request);
        }
        case UPIPE_UNREGISTER_REQUEST: {
            struct urequest *request = va_arg(args, struct urequest *);
            if (request->type == UREQUEST_FLOW_FORMAT ||
                request->type == UREQUEST_UBUF_MGR)
                return UBASE_ERR_NONE;
            return upipe_speexdsp_free_output_proxy(upipe, request);
        }

        case UPIPE_GET_OUTPUT: {
            struct upipe **p = va_arg(args, struct upipe **);
            return upipe_speexdsp_get_output(upipe, p);
        }
        case UPIPE_SET_OUTPUT: {
            struct upipe *output = va_arg(args, struct upipe *);
            return upipe_speexdsp_set_output(upipe, output);
        }
        case UPIPE_GET_FLOW_DEF: {
            struct uref **p = va_arg(args, struct uref **);
            return upipe_speexdsp_get_flow_def(upipe, p);
        }
        case UPIPE_SET_FLOW_DEF: {
            struct uref *flow = va_arg(args, struct uref *);
            return upipe_speexdsp_set_flow_def(upipe, flow);
        }
        case UPIPE_SET_OPTION: {
            const char *option = va_arg(args, const char *);
            const char *value  = va_arg(args, const char *);
            if (strcmp(option, "quality"))
                return UBASE_ERR_INVALID;
            if (upipe_speexdsp->ctx)
                return UBASE_ERR_BUSY;
            int quality = atoi(value);
            if (quality > SPEEX_RESAMPLER_QUALITY_MAX) {
                quality = SPEEX_RESAMPLER_QUALITY_MAX;
                upipe_err_va(upipe, "Clamping quality to %d",
                        SPEEX_RESAMPLER_QUALITY_MAX);
            } else if (quality < SPEEX_RESAMPLER_QUALITY_MIN) {
                quality = SPEEX_RESAMPLER_QUALITY_MIN;
                upipe_err_va(upipe, "Clamping quality to %d",
                        SPEEX_RESAMPLER_QUALITY_MIN);
            }
            upipe_speexdsp->quality = quality;
            return UBASE_ERR_NONE;
        }

        default:
            return UBASE_ERR_UNHANDLED;
    }
}

/** @internal @This allocates a speexdsp pipe.
 *
 * @param mgr common management structure
 * @param uprobe structure used to raise events
 * @param signature signature of the pipe allocator
 * @param args optional arguments
 * @return pointer to upipe or NULL in case of allocation error
 */
static struct upipe *upipe_speexdsp_alloc(struct upipe_mgr *mgr,
                                     struct uprobe *uprobe,
                                     uint32_t signature, va_list args)
{
    struct upipe *upipe = upipe_speexdsp_alloc_void(mgr, uprobe, signature,
                                               args);
    if (unlikely(upipe == NULL))
        return NULL;

    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);

    upipe_speexdsp->ctx = NULL;
    upipe_speexdsp->drift_rate = (struct urational){ 0, 0 };
    upipe_speexdsp->quality = SPEEX_RESAMPLER_QUALITY_MAX;

    upipe_speexdsp_init_urefcount(upipe);
    upipe_speexdsp_init_ubuf_mgr(upipe);
    upipe_speexdsp_init_output(upipe);
    upipe_speexdsp_init_flow_def(upipe);
    upipe_speexdsp_init_input(upipe);

    upipe_throw_ready(upipe);
    return upipe;
}

/** @This frees a upipe.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_speexdsp_free(struct upipe *upipe)
{
    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);
    if (likely(upipe_speexdsp->ctx))
        speex_resampler_destroy(upipe_speexdsp->ctx);

    upipe_throw_dead(upipe);
    upipe_speexdsp_clean_input(upipe);
    upipe_speexdsp_clean_output(upipe);
    upipe_speexdsp_clean_flow_def(upipe);
    upipe_speexdsp_clean_ubuf_mgr(upipe);
    upipe_speexdsp_clean_urefcount(upipe);
    upipe_speexdsp_free_void(upipe);
}

/** module manager static descriptor */
static struct upipe_mgr upipe_speexdsp_mgr = {
    .refcount = NULL,
    .signature = UPIPE_SPEEXDSP_SIGNATURE,

    .upipe_alloc = upipe_speexdsp_alloc,
    .upipe_input = upipe_speexdsp_input,
    .upipe_control = upipe_speexdsp_control,

    .upipe_mgr_control = NULL
};

/** @This returns the management structure for speexdsp pipes
 *
 * @return pointer to manager
 */
struct upipe_mgr *upipe_speexdsp_mgr_alloc(void)
{
    return &upipe_speexdsp_mgr;
}
Exemplo n.º 18
0
/** avcdec callback */
static int avcdec_catch(struct uprobe *uprobe, struct upipe *upipe,
                        int event, va_list args)
{
    if (event != UPROBE_NEED_OUTPUT)
        return uprobe_throw_next(uprobe, upipe, event, args);

    struct uref *flow_def = va_arg(args, struct uref *);

    uint64_t hsize, vsize, wanted_hsize;
    struct urational sar;
    bool progressive;
    if (unlikely(!ubase_check(uref_pic_flow_get_hsize(flow_def, &hsize)) ||
                 !ubase_check(uref_pic_flow_get_vsize(flow_def, &vsize)) ||
                 !ubase_check(uref_pic_flow_get_sar(flow_def, &sar)))) {
        upipe_err_va(upipe, "incompatible flow def");
        upipe_release(upipe_source);
        return UBASE_ERR_UNHANDLED;
    }
    wanted_hsize = (hsize * sar.num / sar.den / 2) * 2;
    progressive = ubase_check(uref_pic_get_progressive(flow_def));

    struct uref *flow_def2 = uref_dup(flow_def);
    upipe_use(upipe);

    if (!progressive) {
        uref_pic_set_progressive(flow_def2);
        struct upipe *deint = upipe_void_alloc_output(upipe,
                upipe_filter_blend_mgr,
                uprobe_pfx_alloc(uprobe_use(logger),
                                 loglevel, "deint"));
        assert(deint != NULL);
        upipe_release(upipe);
        upipe = deint;
    }

    if (wanted_hsize != hsize) {
        uref_pic_flow_set_hsize(flow_def2, wanted_hsize);
        struct upipe *sws = upipe_flow_alloc_output(upipe, upipe_sws_mgr,
                uprobe_pfx_alloc_va(uprobe_use(logger),
                                    loglevel, "sws"), flow_def2);
        assert(sws != NULL);
        upipe_release(upipe);
        upipe = sws;
    }

    uref_pic_flow_clear_format(flow_def2);
    uref_flow_set_def(flow_def2, "block.mjpeg.pic.");
    struct upipe *jpegenc = upipe_flow_alloc_output(upipe, upipe_avcenc_mgr,
            uprobe_pfx_alloc_va(uprobe_use(logger),
                                loglevel, "jpeg"), flow_def2);
    assert(jpegenc != NULL);
    upipe_release(upipe);
    upipe_set_option(jpegenc, "qmax", "2");
    upipe = jpegenc;

    struct upipe *urefprobe = upipe_void_alloc_output(upipe,
            upipe_probe_uref_mgr,
            uprobe_pfx_alloc_va(uprobe_use(&uprobe_uref),
                                loglevel, "urefprobe"));
    assert(urefprobe != NULL);
    upipe_release(upipe);
    upipe = urefprobe;

    struct upipe *fsink = upipe_void_alloc_output(upipe, upipe_fsink_mgr,
            uprobe_pfx_alloc_va(uprobe_use(logger),
            ((loglevel > UPROBE_LOG_DEBUG) ? UPROBE_LOG_WARNING : loglevel),
            "jpegsink"));
    assert(fsink != NULL);
    upipe_release(upipe);
    upipe_fsink_set_path(fsink, dstpath, UPIPE_FSINK_OVERWRITE);
    upipe = fsink;

    uref_free(flow_def2);
    upipe_release(upipe);
    return UBASE_ERR_NONE;
}
Exemplo n.º 19
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static inline void upipe_rtpd_input(struct upipe *upipe, struct uref *uref,
                                    struct upump **upump_p)
{
    struct upipe_rtpd *upipe_rtpd = upipe_rtpd_from_upipe(upipe);
    uint8_t rtp_buffer[RTP_HEADER_SIZE];
    const uint8_t *rtp_header = uref_block_peek(uref, 0, RTP_HEADER_SIZE, 
                                                rtp_buffer);
    if (unlikely(rtp_header == NULL)) {
        upipe_warn(upipe, "invalid buffer received");
        uref_free(uref);
        return;
    }

    bool valid = rtp_check_hdr(rtp_header);
    bool extension = rtp_check_extension(rtp_header);
    uint8_t cc = rtp_get_cc(rtp_header);
    uint8_t type = rtp_get_type(rtp_header);
    uint16_t seqnum = rtp_get_seqnum(rtp_header);
    ptrdiff_t extension_offset = rtp_extension((uint8_t *)rtp_header) -
                                 rtp_header;
    uref_block_peek_unmap(uref, 0, rtp_buffer, rtp_header);

    if (unlikely(!valid)) {
        upipe_warn(upipe, "invalid RTP header");
        uref_free(uref);
        return;
    }

    size_t offset = RTP_HEADER_SIZE + 4 * cc;

    if (extension) {
        rtp_header = uref_block_peek(uref, extension_offset,
                                     RTP_EXTENSION_SIZE, rtp_buffer);
        if (unlikely(rtp_header == NULL)) {
            upipe_warn(upipe, "invalid buffer received");
            uref_free(uref);
            return;
        }
        offset += 4 * (1 + rtpx_get_length(rtp_header));
        uref_block_peek_unmap(uref, extension_offset, rtp_buffer, rtp_header);
    }

    if (unlikely(upipe_rtpd->expected_seqnum != -1 &&
                 seqnum != upipe_rtpd->expected_seqnum)) {
        upipe_warn_va(upipe, "potentially lost %d RTP packets",
                      (seqnum + UINT16_MAX + 1 - upipe_rtpd->expected_seqnum) &
                      UINT16_MAX);
        uref_flow_set_discontinuity(uref);
    }
    upipe_rtpd->expected_seqnum = seqnum + 1;
    upipe_rtpd->expected_seqnum &= UINT16_MAX;

    if (unlikely(type != upipe_rtpd->type)) {
        assert(upipe_rtpd->flow_def_input != NULL);
        struct uref *flow_def = uref_dup(upipe_rtpd->flow_def_input);
        if (unlikely(flow_def == NULL)) {
            uref_free(uref);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }

        switch (type) {
            case RTP_TYPE_TS:
                uref_flow_set_def(flow_def, "block.mpegtsaligned.");
                break;
            default:
                break;
        }
        upipe_rtpd->type = type;
        upipe_rtpd_store_flow_def(upipe, flow_def);
    }

    uref_block_resize(uref, offset, -1);
    upipe_rtpd_output(upipe, uref, upump_p);
}
Exemplo n.º 20
0
/** @internal @This parses a new s337 header.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_s337d_parse_preamble(struct upipe *upipe)
{
    struct upipe_s337d *upipe_s337d = upipe_s337d_from_upipe(upipe);
    uint8_t preamble[S337_PREAMBLE_SIZE];
    if (!ubase_check(uref_block_extract(upipe_s337d->next_uref, 0,
                    S337_PREAMBLE_SIZE, preamble)))
        return; /* not enough data */

    uint8_t data_type = s337_get_data_type(preamble);
    uint8_t data_mode = s337_get_data_mode(preamble);
    bool error = s337_get_error(preamble);
    uint8_t data_stream = s337_get_data_stream(preamble);
    uint8_t data_type_dep = s337_get_data_type_dep(preamble);
    upipe_s337d->next_frame_size = s337_get_length(preamble) + 7;
    upipe_s337d->next_frame_size /= 8;

    if (data_type != S337_TYPE_A52 && data_type != S337_TYPE_A52E) {
        upipe_s337d->next_frame_discard = true;
        return;
    }

    if (data_mode != S337_MODE_16) {
        upipe_err_va(upipe, "unsupported data mode (%"PRIu8")", data_mode);
        upipe_s337d->next_frame_discard = true;
        return;
    }

    upipe_s337d->next_frame_discard = false;
    if (error)
        upipe_warn(upipe, "error flag set");

    if (upipe_s337d->data_stream != data_stream) {
        upipe_dbg_va(upipe, "now following stream %"PRIu8, data_stream);
        upipe_s337d->data_stream = data_stream;
    }

    if (upipe_s337d->data_type == data_type)
        return;
    upipe_s337d->data_type = data_type;

    if (data_type_dep & S337_TYPE_A52_REP_RATE_FLAG)
        upipe_warn(upipe, "repetition rate flag set");
    if (data_type_dep & S337_TYPE_A52_NOT_FULL_SVC)
        upipe_warn(upipe, "not full service flag set");

    struct uref *flow_def = upipe_s337d_alloc_flow_def_attr(upipe);
    if (unlikely(flow_def == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    if (data_type == S337_TYPE_A52)
        UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.ac3.sound."))
    else
        UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.eac3.sound."))

    flow_def = upipe_s337d_store_flow_def_attr(upipe, flow_def);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }
    upipe_s337d_store_flow_def(upipe, flow_def);
}
Exemplo n.º 21
0
static int upipe_m3u_reader_key(struct upipe *upipe,
                                struct uref *flow_def,
                                const char *line)
{
    struct upipe_m3u_reader *upipe_m3u_reader =
        upipe_m3u_reader_from_upipe(upipe);

    if (unlikely(!ubase_check(uref_flow_match_def(flow_def,
                                                  M3U_FLOW_DEF))) &&
        unlikely(!ubase_check(uref_flow_match_def(flow_def,
                                                  PLAYLIST_FLOW_DEF))))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, PLAYLIST_FLOW_DEF));

    struct uref *key = uref_sibling_alloc_control(flow_def);
    if (unlikely(key == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }

    if (upipe_m3u_reader->key)
        uref_free(upipe_m3u_reader->key);
    upipe_m3u_reader->key = key;

    const char *iterator = line;
    struct ustring name, value;
    while (ubase_check(attribute_iterate(&iterator, &name, &value)) &&
           iterator != NULL) {
        char value_str[value.len + 1];
        int err = ustring_cpy(value, value_str, sizeof (value_str));
        if (unlikely(!ubase_check(err))) {
            upipe_err_va(upipe, "fail to copy ustring %.*s",
                         (int)value.len, value.at);
            continue;
        }

        if (!ustring_cmp_str(name, "METHOD")) {
            err = uref_m3u_playlist_key_set_method(key, value_str);
            if (unlikely(!ubase_check(err)))
                upipe_err_va(upipe, "fail to set key method to %s", value_str);
        }
        else if (!ustring_cmp_str(name, "URI")) {
            err = uref_m3u_playlist_key_set_uri(key, value_str);
            if (unlikely(!ubase_check(err)))
                upipe_err_va(upipe, "fail to set uri to %s", value_str);
        }
        else if (!ustring_cmp_str(name, "IV")) {
            size_t len = strlen(value_str);
            if (unlikely(len > 32)) {
                upipe_warn_va(upipe, "invalid initialization vector %s",
                              value_str);
                continue;
            }
            for (unsigned i = 0; i < len; i += 2) {
                if (unlikely(!isxdigit(value_str[i])) ||
                    unlikely(!isxdigit(value_str[i + 1]))) {
                    upipe_warn_va(upipe, "invalid initialization vector %s",
                                  value_str);
                    continue;
                }
                //FIXME
                //iv[] = value_str[i]
            }

        }
        else {
            upipe_warn_va(upipe, "ignoring attribute %.*s (%.*s)",
                          (int)name.len, name.at, (int)value.len, value.at);
        }
    }

    return UBASE_ERR_NONE;
}
Exemplo n.º 22
0
/** @internal @This parses A/52 Annex E header.
 *
 * @param upipe description structure of the pipe
 * @return false in case the header is inconsistent
 */
static bool upipe_a52f_parse_a52e(struct upipe *upipe)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    uint8_t header[A52_SYNCINFO_SIZE];
    if (unlikely(!ubase_check(uref_block_extract(upipe_a52f->next_uref, 0,
                                                 sizeof(header), header))))
        return true; /* not enough data */

    if (likely(a52e_sync_compare_formats(header, upipe_a52f->sync_header))) {
        /* identical sync */
        upipe_a52f->next_frame_size =
            a52e_get_frame_size(a52e_get_frmsiz(header));
        return true;
    }

    /* sample rate */
    uint64_t samplerate;
    switch (a52e_get_fscod(header)) {
        case A52_FSCOD_48KHZ:
            samplerate = 48000;
            break;
        case A52_FSCOD_441KHZ:
            samplerate = 44100;
            break;
        case A52_FSCOD_32KHZ:
            samplerate = 32000;
            break;
        case A52_FSCOD_RESERVED:
            switch (a52e_get_fscod2(header)) {
                case A52E_FSCOD2_24KHZ:
                    samplerate = 24000;
                    break;
                case A52E_FSCOD2_2205KHZ:
                    samplerate = 22050;
                    break;
                case A52E_FSCOD2_16KHZ:
                    samplerate = 16000;
                    break;
                default:
                    upipe_warn(upipe, "reserved fscod2");
                    return false;
            }
            break;
        default: /* never reached */
            return false;
    }

    /* frame size */
    upipe_a52f->next_frame_size = a52e_get_frame_size(a52e_get_frmsiz(header));

    /* channels */
    int acmod = a52e_get_acmod(header);
    int channels = acmod_chans[acmod].nfchans + a52e_get_lfeon(header);

    uint64_t octetrate =
          (upipe_a52f->next_frame_size * samplerate + A52_FRAME_SAMPLES - 1) /
          A52_FRAME_SAMPLES;
    memcpy(upipe_a52f->sync_header, header, A52_SYNCINFO_SIZE);
    upipe_a52f->samplerate = samplerate;

    struct uref *flow_def = upipe_a52f_alloc_flow_def_attr(upipe);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return false;
    }

    UBASE_FATAL(upipe, uref_flow_set_complete(flow_def))
    UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.eac3.sound."))
    UBASE_FATAL(upipe, uref_sound_flow_set_samples(flow_def, A52_FRAME_SAMPLES))
    UBASE_FATAL(upipe, uref_sound_flow_set_rate(flow_def, samplerate))
    UBASE_FATAL(upipe, uref_sound_flow_set_channels(flow_def, channels))
    UBASE_FATAL(upipe, uref_clock_set_latency(flow_def,
                upipe_a52f->input_latency +
                UCLOCK_FREQ * A52_FRAME_SAMPLES / samplerate))
    UBASE_FATAL(upipe, uref_block_flow_set_octetrate(flow_def, octetrate))

    flow_def = upipe_a52f_store_flow_def_attr(upipe, flow_def);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return false;
    }
    upipe_a52f_store_flow_def(upipe, flow_def);

    return true;
}
Exemplo n.º 23
0
/** @internal @This parses A/52 header.
 *
 * @param upipe description structure of the pipe
 * @return false in case the header is inconsistent
 */
static bool upipe_a52f_parse_a52(struct upipe *upipe)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    uint8_t header[A52_SYNCINFO_SIZE + 2];
    if (unlikely(!ubase_check(uref_block_extract(upipe_a52f->next_uref, 0,
                                                 sizeof(header), header))))
        return true; /* not enough data */

    ssize_t next_frame_size = a52_get_frame_size(a52_get_fscod(header),
                                                 a52_get_frmsizecod(header));
    if (!next_frame_size)
        return false;

    if (likely(a52_sync_compare_formats(header, upipe_a52f->sync_header) &&
               header[5] == upipe_a52f->sync_header[5] &&
               header[6] == upipe_a52f->sync_header[6])) {
        /* identical sync */
        upipe_a52f->next_frame_size = next_frame_size;
        return true;
    }

    /* sample rate */
    uint64_t samplerate;
    switch (a52_get_fscod(header)) {
        case A52_FSCOD_48KHZ:
            samplerate = 48000;
            break;
        case A52_FSCOD_441KHZ:
            samplerate = 44100;
            break;
        case A52_FSCOD_32KHZ:
            samplerate = 32000;
            break;
        default:
            upipe_warn(upipe, "reserved fscod");
            return false;
    }

    /* frame size */
    upipe_a52f->next_frame_size = next_frame_size;

    /* channels */
    int acmod = a52_get_acmod(header);
    int channels = acmod_chans[acmod].nfchans +
        ((header[6] >> (4 - acmod_chans[acmod].lfe_offset)) & 1);

    uint64_t octetrate = a52_bitrate_tab[a52_get_frmsizecod(header)] * 1000 / 8;
    memcpy(upipe_a52f->sync_header, header, A52_SYNCINFO_SIZE + 2);
    upipe_a52f->samplerate = samplerate;

    struct uref *flow_def = upipe_a52f_alloc_flow_def_attr(upipe);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return false;
    }

    UBASE_FATAL(upipe, uref_flow_set_complete(flow_def))
    UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.ac3.sound."))
    UBASE_FATAL(upipe, uref_sound_flow_set_samples(flow_def, A52_FRAME_SAMPLES))
    UBASE_FATAL(upipe, uref_sound_flow_set_rate(flow_def, samplerate))
    UBASE_FATAL(upipe, uref_sound_flow_set_channels(flow_def, channels))
    UBASE_FATAL(upipe, uref_clock_set_latency(flow_def,
                upipe_a52f->input_latency +
                UCLOCK_FREQ * A52_FRAME_SAMPLES / samplerate))
    UBASE_FATAL(upipe, uref_block_flow_set_octetrate(flow_def, octetrate))

    flow_def = upipe_a52f_store_flow_def_attr(upipe, flow_def);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return false;
    }
    upipe_a52f_store_flow_def(upipe, flow_def);

    return true;
}
Exemplo n.º 24
0
static int upipe_m3u_reader_process_media(struct upipe *upipe,
                                          struct uref *flow_def,
                                          const char *line)
{
    struct upipe_m3u_reader *upipe_m3u_reader =
        upipe_m3u_reader_from_upipe(upipe);

    if (!ubase_check(uref_flow_match_def(flow_def, M3U_FLOW_DEF)) &&
        !ubase_check(uref_flow_match_def(flow_def, MASTER_FLOW_DEF)))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, MASTER_FLOW_DEF));

    struct uref *item = uref_sibling_alloc_control(flow_def);
    if (unlikely(item == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }

    struct ustring name, value;
    while (ubase_check(attribute_iterate(&line, &name, &value)) && line) {
        if (!ustring_cmp_str(name, "URI")) {
            value = ustring_unframe(value, '"');
            char val[value.len + 1];
            int err = ustring_cpy(value, val, sizeof (val));
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to copy %.*s",
                              (int)value.len, value.at);
                continue;
            }
            err = uref_m3u_set_uri(item, val);
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to set uri %s", val);
                continue;
            }
        }
        else if (!ustring_cmp_str(name, "TYPE")) {
            char val[value.len + 1];
            int err = ustring_cpy(value, val, sizeof (val));
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to copy %.*s",
                              (int)value.len, value.at);
                continue;
            }
            err = uref_m3u_master_set_media_type(item, val);
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to set media type %s", val);
                continue;
            }
        }
        else if (!ustring_cmp_str(name, "DEFAULT")) {
            if (!ustring_cmp_str(value, "YES")) {
                int err = uref_m3u_master_set_media_default(item);
                if (unlikely(!ubase_check(err)))
                    continue;
            }
            else if (ustring_cmp_str(value, "NO")) {
                upipe_warn_va(upipe, "invalid DEFAULT value %.*s",
                              (int)value.len, value.at);
                continue;
            }
        }
        else if (!ustring_cmp_str(name, "AUTOSELECT")) {
            if (!ustring_cmp_str(value, "YES")) {
                int err = uref_m3u_master_set_media_autoselect(item);
                if (unlikely(!ubase_check(err)))
                    continue;
            }
            else if (ustring_cmp_str(value, "NO")) {
                upipe_warn_va(upipe, "invalid AUTOSELECT value %.*s",
                              (int)value.len, value.at);
                continue;
            }
        }
        else if (!ustring_cmp_str(name, "NAME")) {
            value = ustring_unframe(value, '"');
            char val[value.len + 1];
            int err = ustring_cpy(value, val, sizeof (val));
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to copy %.*s",
                              (int)value.len, value.at);
                continue;
            }
            err = uref_m3u_master_set_media_name(item, val);
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to set media name %s", val);
                continue;
            }
        }
        else if (!ustring_cmp_str(name, "GROUP-ID")) {
            value = ustring_unframe(value, '"');
            char val[value.len + 1];
            int err = ustring_cpy(value, val, sizeof (val));
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to copy %.*s",
                              (int)value.len, value.at);
                continue;
            }
            err = uref_m3u_master_set_media_group(item, val);
            if (unlikely(!ubase_check(err))) {
                upipe_warn_va(upipe, "fail to set group id %s", val);
                continue;
            }
        }
        else {
            upipe_warn_va(upipe, "ignoring attribute %.*s (%.*s)",
                          (int)name.len, name.at,
                          (int)value.len, value.at);
        }
    }
    ulist_add(&upipe_m3u_reader->items, uref_to_uchain(item));
    return UBASE_ERR_NONE;
}