Example #1
0
/** @internal @This returns the index of an interface
 *
 * @param upipe description structure of the pipe
 * @param name interface name
 * @return interface index
 */
static bool upipe_udp_get_ifindex(struct upipe *upipe, const char *name, int *ifrindex)
{
#if !defined(__APPLE__) && !defined(__native_client__)
    int fd;
    struct ifreq ifr;

    if (! (name && ifrindex && upipe) ) {
        return false;
    }

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        upipe_err_va(upipe, "unable to open socket (%m)");
        return false;
    }

    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ-1] = '\0';

    if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
        upipe_err_va(upipe, "unable to get interface index (%m)");
        close(fd);
        return false;
    }

    close(fd);

    *ifrindex = ifr.ifr_ifindex;
    return true;
#else
    upipe_err_va(upipe, "unable to get interface index (%m)");
    return false;
#endif
}
Example #2
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;
}
Example #3
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_fdec_set_flow_def(struct upipe *upipe, struct uref *flow_def)
{
    struct upipe_fdec_mgr *fdec_mgr = upipe_fdec_mgr_from_upipe_mgr(upipe->mgr);
    struct upipe_fdec *upipe_fdec = upipe_fdec_from_upipe(upipe);
    if (flow_def == NULL)
        return UBASE_ERR_INVALID;

    if (upipe_fdec->last_inner != NULL) {
        if (ubase_check(upipe_set_flow_def(upipe_fdec->last_inner, flow_def)))
            return UBASE_ERR_NONE;
    }
    upipe_fdec_store_bin_input(upipe, NULL);
    upipe_fdec_store_bin_output(upipe, NULL);

    struct upipe *avcdec = upipe_void_alloc(fdec_mgr->avcdec_mgr,
            uprobe_pfx_alloc(
                uprobe_use(&upipe_fdec->last_inner_probe),
                UPROBE_LOG_VERBOSE, "avcdec"));

    if (unlikely(avcdec == NULL)) {
        upipe_err_va(upipe, "couldn't allocate avcdec");
        return UBASE_ERR_UNHANDLED;
    }
    if (unlikely(!ubase_check(upipe_set_flow_def(avcdec, flow_def)))) {
        upipe_err_va(upipe, "couldn't set avcdec flow def");
        upipe_release(avcdec);
        return UBASE_ERR_UNHANDLED;
    }
    if (upipe_fdec->options != NULL && upipe_fdec->options->udict != NULL) {
        const char *key = NULL;
        enum udict_type type = UDICT_TYPE_END;
        while (ubase_check(udict_iterate(upipe_fdec->options->udict, &key,
                                         &type)) && type != UDICT_TYPE_END) {
            const char *value;
            if (key == NULL ||
                !ubase_check(udict_get_string(upipe_fdec->options->udict,
                                              &value, type, key)))
                continue;
            if (!ubase_check(upipe_set_option(avcdec, key, value)))
                upipe_warn_va(upipe, "option %s=%s invalid", key, value);
        }
    }

    upipe_fdec_store_bin_input(upipe, upipe_use(avcdec));
    upipe_fdec_store_bin_output(upipe, avcdec);
    return UBASE_ERR_NONE;
}
Example #4
0
static void upipe_dveo_asi_sink_stats(struct upipe *upipe)
{
    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);
    int fd = upipe_dveo_asi_sink->fd;

    static uint64_t sum;
    sum += 188;
    //upipe_notice_va(upipe, "Wrote %"PRIu64" bytes into the card", sum);

    int val;

    if (ioctl(fd, ASI_IOC_TXGETEVENTS, &val) < 0)
        upipe_err_va(upipe, "ioctl TXGETEVENTS failed (%m)");
    else {
        if (val & ASI_EVENT_TX_BUFFER)
            upipe_notice(upipe, "driver transmit buffer queue underrun");
        if (val & ASI_EVENT_TX_FIFO)
            upipe_notice(upipe, "onboard transmit FIFO underrun");
        if (val & ASI_EVENT_TX_DATA) {
            upipe_notice(upipe, "transmit data status change");
            if (ioctl(fd, ASI_IOC_TXGETTXD, &val) < 0)
                upipe_err_va(upipe, "ioctl TXGETTXDfailed (%m)");
            else
                upipe_notice_va(upipe, "transmitting: %d", val);
        }
    }

    if (ioctl(fd, ASI_IOC_TXGETBUFLEVEL, &val) < 0)
        upipe_err_va(upipe, "ioctl TXGETBUFLEVEL failed (%m)");
    else {
        static int old;
#define MARGIN 2
        if ((val - MARGIN) >  old || (val + MARGIN) < old) {
            float secs = (float)val * 6 * 196 * 8 / 10500000;
            upipe_notice_va(upipe, "buf level %d -> %.2fs", val, secs);
            old = val;
        }
    }

    if (ioctl(fd, ASI_IOC_TXGETBYTECOUNT, &val) < 0)
        upipe_err_va(upipe, "ioctl TXGETBYTECOUNTfailed (%m)");
    else {
        /*static uint64_t byte_sum;
        byte_sum += val;
        upipe_notice_va(upipe, "byte count %d -> %"PRIu64, val, byte_sum);*/
    }
}
Example #5
0
/** @internal @This allocates a block_to_sound 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_block_to_sound_alloc(struct upipe_mgr *mgr,
                                      struct uprobe *uprobe,
                                      uint32_t signature, va_list args)
{
    struct uref *flow_def;

    struct upipe *upipe = upipe_block_to_sound_alloc_flow(mgr, uprobe, signature, args, &flow_def);
    if (unlikely(upipe == NULL))
        return NULL;

    struct upipe_block_to_sound *upipe_block_to_sound = upipe_block_to_sound_from_upipe(upipe);

    if (unlikely(!ubase_check(uref_sound_flow_get_planes(flow_def,
            &upipe_block_to_sound->planes)) || upipe_block_to_sound->planes != 1 )) {
        upipe_err_va(upipe, "wrong number of planes: %d", upipe_block_to_sound->planes);
        upipe_block_to_sound_free_flow(upipe);
        uref_free(flow_def);
        return NULL;
    }

    if (unlikely(!ubase_check(uref_sound_flow_get_sample_size(flow_def,
            &upipe_block_to_sound->sample_size)))) {
        upipe_err_va(upipe, "flow def needs sample_size");
        upipe_block_to_sound_free_flow(upipe);
        uref_free(flow_def);
        return NULL;
    }

    upipe_block_to_sound->flow_def_config = flow_def;

    upipe_block_to_sound_init_urefcount(upipe);
    upipe_block_to_sound_init_output(upipe);
    upipe_block_to_sound_init_ubuf_mgr(upipe);

    upipe_throw_ready(upipe);

    return upipe;
}
Example #6
0
/** @This starts the watcher waiting for the sink to unblock.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_dveo_asi_sink_poll(struct upipe *upipe)
{
    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);
    if (unlikely(!ubase_check(upipe_dveo_asi_sink_check_upump_mgr(upipe)))) {
        upipe_err_va(upipe, "can't get upump_mgr");
        upipe_throw_fatal(upipe, UBASE_ERR_UPUMP);
        return;
    }
    struct upump *watcher = upump_alloc_fd_write(upipe_dveo_asi_sink->upump_mgr,
            upipe_dveo_asi_sink_watcher, upipe, upipe->refcount, upipe_dveo_asi_sink->fd);
    if (unlikely(watcher == NULL)) {
        upipe_err(upipe, "can't create watcher");
        upipe_throw_fatal(upipe, UBASE_ERR_UPUMP);
    } else {
        upipe_dveo_asi_sink_set_upump(upipe, watcher);
        upump_start(watcher);
    }
}
Example #7
0
/** split callback */
static int split_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);

    upipe_release(upipe_split_output);
    upipe_split_output = upipe_use(upipe);

    struct upipe *avcdec = upipe_void_alloc_output(upipe, upipe_avcdec_mgr,
            uprobe_pfx_alloc_va(uprobe_use(&uprobe_avcdec),
                                loglevel, "avcdec"));
    if (avcdec == NULL) {
        upipe_err_va(upipe, "incompatible flow def");
        upipe_release(upipe_source);
        return UBASE_ERR_UNHANDLED;
    }
    upipe_release(avcdec);
    return UBASE_ERR_NONE;
}
Example #8
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);
}
Example #9
0
static uint64_t upipe_dveo_asi_sink_now(struct uclock *uclock)
{
    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_uclock(uclock);

    if (upipe_dveo_asi_sink->fd < 0)
        return 0;

    unsigned int val;
    struct upipe *upipe = &upipe_dveo_asi_sink->upipe;
    if (ioctl(upipe_dveo_asi_sink->fd, ASI_IOC_TXGET27COUNT, &val) < 0) {
        upipe_err_va(upipe, "can't get hardware clock (%m)");
        return 0;
    }

    if (val < upipe_dveo_asi_sink->last_val) {
        upipe_notice(upipe, "clock wrapping");
        upipe_dveo_asi_sink->wraparounds++;
    }

    upipe_dveo_asi_sink->last_val = val;

    return (upipe_dveo_asi_sink->wraparounds << 32) + val;
}
Example #10
0
/** @internal @This checks and creates the upump watcher to wait for the
 * availability of the queue.
 *
 * @param upipe description structure of the pipe
 * @return false in case of error
 */
static bool upipe_nacl_audio_check_watcher(struct upipe *upipe)
{
    struct upipe_nacl_audio *upipe_nacl_audio =
        upipe_nacl_audio_from_upipe(upipe);
    if (likely(upipe_nacl_audio->upump != NULL))
        return true;

    upipe_nacl_audio_check_upump_mgr(upipe);
    if (upipe_nacl_audio->upump_mgr == NULL)
        return false;

    struct upump *upump =
        uqueue_upump_alloc_push(&upipe_nacl_audio->uqueue,
                                upipe_nacl_audio->upump_mgr,
                                upipe_nacl_audio_watcher, upipe,
                                upipe->refcount);
    if (unlikely(upump == NULL)) {
        upipe_err_va(upipe, "can't create watcher");
        upipe_throw_fatal(upipe, UBASE_ERR_UPUMP);
        return false;
    }
    upipe_nacl_audio_set_upump(upipe, upump);
    return true;
}
Example #11
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;
}
Example #12
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;
}
Example #13
0
/** @internal @This asks to open the given file.
 *
 * @param upipe description structure of the pipe
 * @param path relative or absolute path of the file
 * @param mode mode of opening the file
 * @return an error code
 */
static int _upipe_fsink_set_path(struct upipe *upipe, const char *path,
                                 enum upipe_fsink_mode mode)
{
    struct upipe_fsink *upipe_fsink = upipe_fsink_from_upipe(upipe);

    if (unlikely(upipe_fsink->fd != -1)) {
        if (likely(upipe_fsink->path != NULL))
            upipe_notice_va(upipe, "closing file %s", upipe_fsink->path);
        close(upipe_fsink->fd);
    }
    free(upipe_fsink->path);
    upipe_fsink->path = NULL;
    upipe_fsink_set_upump(upipe, NULL);
    if (!upipe_fsink_check_input(upipe))
        /* Release the pipe used in @ref upipe_fsink_input. */
        upipe_release(upipe);

    if (unlikely(path == NULL))
        return UBASE_ERR_NONE;

    upipe_fsink_check_upump_mgr(upipe);

    const char *mode_desc = NULL; /* hush gcc */
    int flags;
    switch (mode) {
        case UPIPE_FSINK_NONE:
            flags = 0;
            break;
        case UPIPE_FSINK_APPEND:
            mode_desc = "append";
            flags = O_CREAT;
            break;
        case UPIPE_FSINK_OVERWRITE:
            mode_desc = "overwrite";
            flags = O_CREAT | O_TRUNC;
            break;
        case UPIPE_FSINK_CREATE:
            mode_desc = "create";
            flags = O_CREAT | O_EXCL;
            break;
        default:
            upipe_err_va(upipe, "invalid mode %d", mode);
            return UBASE_ERR_INVALID;
    }
    upipe_fsink->fd = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC | flags,
                           S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (unlikely(upipe_fsink->fd == -1)) {
        upipe_err_va(upipe, "can't open file %s (%s)", path, mode_desc);
        return UBASE_ERR_EXTERNAL;
    }
    switch (mode) {
        /* O_APPEND seeks on each write, so use this instead */
        case UPIPE_FSINK_APPEND:
            if (unlikely(lseek(upipe_fsink->fd, 0, SEEK_END) == -1)) {
                upipe_err_va(upipe, "can't append to file %s (%s)", path, mode_desc);
                close(upipe_fsink->fd);
                upipe_fsink->fd = -1;
                return UBASE_ERR_EXTERNAL;
            }
            break;
        default:
            break;
    }

    upipe_fsink->path = strdup(path);
    if (unlikely(upipe_fsink->path == NULL)) {
        close(upipe_fsink->fd);
        upipe_fsink->fd = -1;
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }
    if (!upipe_fsink_check_input(upipe))
        /* Use again the pipe that we previously released. */
        upipe_use(upipe);
    upipe_notice_va(upipe, "opening file %s in %s mode",
                    upipe_fsink->path, mode_desc);
    return UBASE_ERR_NONE;
}
Example #14
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;
}
Example #15
0
/** @internal @This outputs data to the file sink.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 * @return true if the uref was processed
 */
static bool upipe_dveo_asi_sink_output(struct upipe *upipe, struct uref *uref,
                               struct upump **upump_p)
{
    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        uref_free(uref);
        return true;
    }

    int fd = upipe_dveo_asi_sink->fd;

    if (unlikely(fd == -1)) {
        upipe_warn(upipe, "received a buffer before opening the device");
        uref_free(uref);
        return true;
    }

    uint64_t cr_sys = 0;
    if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys))) || cr_sys == -1) {
        upipe_warn(upipe, "received non-dated buffer");
        uref_free(uref);
        return true;
    }

    if (ubase_check(uref_flow_get_discontinuity(uref))) {
        upipe_warn_va(upipe, "DISCONTINUITY, resetting timestamp");
        upipe_dveo_asi_sink->first_timestamp = true;
    }

    if (unlikely(upipe_dveo_asi_sink->first_timestamp)) {
        int val;
        if (ioctl(fd, ASI_IOC_TXGETTXD, &val) < 0) {
            upipe_err_va(upipe, "ioctl TXGETTXDfailed (%m)");
            upipe_throw_fatal(upipe, UBASE_ERR_UNKNOWN);
            uref_free(uref);
            return true;
        } else if (val) {
            upipe_warn(upipe, "Waiting for transmission to stop");
            uref_free(uref);
            return true;
        }
    }

    /* Make sure we set the counter */
    bool reset_first_timestamp = upipe_dveo_asi_sink->first_timestamp;

    if (upipe_dveo_asi_sink_add_header(upipe, uref, cr_sys)) {
        uref_free(uref);
        return true; /* invalid uref, discarded */
    }

    if (!upipe_dveo_asi_sink_write(upipe, uref, &reset_first_timestamp))
        return false; /* would block */

    uref_free(uref);

    if (reset_first_timestamp)
        upipe_dveo_asi_sink->first_timestamp = true;

    upipe_dveo_asi_sink_stats(upipe);

    return true;
}
Example #16
0
/** @internal @This parses _uri and opens IPv4 & IPv6 sockets
 *
 * @param upipe description structure of the pipe
 * @param _uri socket URI
 * @param ttl packets time-to-live
 * @param bind_port bind port
 * @param connect_port connect port
 * @param weight weight (UNUSED)
 * @param use_tcp Set this to open a tcp socket (instead of udp)
 * @param use_raw open RAW socket (udp)
 * @param raw_header user-provided buffer for RAW header (ip+udp)
 * @return socket fd, or -1 in case of error
 */
int upipe_udp_open_socket(struct upipe *upipe, const char *_uri, int ttl,
                          uint16_t bind_port, uint16_t connect_port,
                          unsigned int *weight, bool *use_tcp,
                          bool *use_raw, uint8_t *raw_header)
{
    union sockaddru bind_addr, connect_addr;
    int fd, i;
    char *uri = strdup(_uri);
    char *token = uri;
    char *token2 = NULL;
    int bind_if_index = 0, connect_if_index = 0;
    in_addr_t if_addr = INADDR_ANY;
    in_addr_t src_addr = INADDR_ANY;
    uint16_t src_port = 4242;
    int tos = 0;
    bool b_tcp;
    bool b_raw;
    int family;
    socklen_t sockaddr_len;
#if !defined(__APPLE__) && !defined(__native_client__)
    char *ifname = NULL;
#endif

    if (!uri)
        return -1;

    memset(&bind_addr, 0, sizeof(union sockaddru));
    memset(&connect_addr, 0, sizeof(union sockaddru));

    bind_addr.ss.ss_family = AF_UNSPEC;
    connect_addr.ss.ss_family = AF_UNSPEC;

    if (use_tcp == NULL) {
        use_tcp = &b_tcp;
    }
    *use_tcp = false;
    if (use_raw == NULL) {
        use_raw = &b_raw;
    }
    *use_raw = false;

    token2 = strrchr(uri, ',');
    if (token2) {
        *token2++ = '\0';
        if (weight) {
            *weight = strtoul(token2, NULL, 0);
        }
    } else if (weight) {
        *weight = 1;
    }

    token2 = strchr(uri, '/');
    if (token2) {
        *token2 = '\0';
    }

    if (*token == '\0') {
        free(uri);
        return -1;
    }

    /* Hosts */
    if (token[0] != '@') {
        if (!upipe_udp_parse_node_service(upipe, token, &token, connect_port,
                                        &connect_if_index, &connect_addr.ss)) {
            free(uri);
            return -1;
        }
        /* required on some architectures */
        memset(&connect_addr.sin.sin_zero, 0, sizeof(connect_addr.sin.sin_zero));
    }

    if (token[0] == '@') {
        token++;
        if (!upipe_udp_parse_node_service(upipe, token, &token, bind_port,
                                        &bind_if_index, &bind_addr.ss)) {
            free(uri);
            return -1;
        }
        /* required on some architectures */
        memset(&bind_addr.sin.sin_zero, 0, sizeof(bind_addr.sin.sin_zero));
    }

    if (bind_addr.ss.ss_family == AF_UNSPEC &&
         connect_addr.ss.ss_family == AF_UNSPEC) {
        free(uri);
        return -1;
    }

    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);

    /* Weights and options */
    if (token2) {
        do {
            *token2++ = '\0';
#define IS_OPTION(option) (!strncasecmp(token2, option, strlen(option)))
#define ARG_OPTION(option) (token2 + strlen(option))
            if (IS_OPTION("ifindex=")) {
                bind_if_index = connect_if_index =
                    strtol(ARG_OPTION("ifindex="), NULL, 0);
            } else if (IS_OPTION("ifaddr=")) {
                char *option = config_stropt(ARG_OPTION("ifaddr="));
                if_addr = inet_addr(option);
                free( option );
#if !defined(__APPLE__) && !defined(__native_client__)
            } else if ( IS_OPTION("ifname=") ) {
                ifname = config_stropt( ARG_OPTION("ifname=") );
                if (strlen(ifname) >= IFNAMSIZ) {
                    ifname[IFNAMSIZ-1] = '\0';
                }
#endif
            } else if (IS_OPTION("srcaddr=")) {
                char *option = config_stropt(ARG_OPTION("srcaddr="));
                src_addr = inet_addr(option);
                free(option);
                *use_raw = true;
            } else if (IS_OPTION("srcport=")) {
                src_port = strtol(ARG_OPTION("srcport="), NULL, 0);
            } else if (IS_OPTION("ttl=")) {
                ttl = strtol(ARG_OPTION("ttl="), NULL, 0);
            } else if (IS_OPTION("tos=")) {
                tos = strtol(ARG_OPTION("tos="), NULL, 0);
            } else if (IS_OPTION("tcp")) {
                *use_tcp = true;
            } else {
                upipe_warn_va(upipe, "unrecognized option %s", token2);
            }
#undef IS_OPTION
#undef ARG_OPTION
        } while ((token2 = strchr(token2, '/')) != NULL);
    }

    if (unlikely(*use_tcp && *use_raw)) {
        upipe_warn(upipe, "RAW sockets not implemented for tcp");
        free(uri);
        return -1;
    }

    free(uri);

    /* Sanity checks */
    if (bind_addr.ss.ss_family != AF_UNSPEC
          && connect_addr.ss.ss_family != AF_UNSPEC
          && bind_addr.ss.ss_family != connect_addr.ss.ss_family) {
        upipe_err(upipe, "incompatible address types");
        return -1;
    }
    if (bind_addr.ss.ss_family != AF_UNSPEC) {
        family = bind_addr.ss.ss_family;
    } else if (connect_addr.ss.ss_family != AF_UNSPEC) {
        family = connect_addr.ss.ss_family;
    } else {
        upipe_err(upipe, "ambiguous address declaration");
        return -1;
    }
    sockaddr_len = (family == AF_INET) ? sizeof(struct sockaddr_in) :
                     sizeof(struct sockaddr_in6);

    if (bind_if_index && connect_if_index
          && bind_if_index != connect_if_index) {
        upipe_err(upipe, "incompatible bind and connect interfaces");
        return -1;
    }
    if (connect_if_index) bind_if_index = connect_if_index;
    else connect_if_index = bind_if_index;

    /* RAW header */
    if (*use_raw && raw_header) {
        upipe_udp_raw_fill_headers(upipe, raw_header,
                src_addr, connect_addr.sin.sin_addr.s_addr, src_port,
                ntohs(connect_addr.sin.sin_port), ttl, tos, 0);
    }


    /* Socket configuration */
    int sock_type = SOCK_DGRAM;
    if (*use_tcp) sock_type = SOCK_STREAM;
    if (*use_raw) sock_type = SOCK_RAW;
    int sock_proto = (*use_raw ? IPPROTO_RAW : 0);

    if ((fd = socket(family, sock_type, sock_proto)) < 0) {
        upipe_err_va(upipe, "unable to open socket (%m)");
        return -1;
    }
    #if !defined(__APPLE__) && !defined(__native_client__)
    if (*use_raw) {
        int hincl = 1;
        if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) {
            upipe_err_va(upipe, "unable to set IP_HDRINCL");
            close(fd);
            return -1;
        }
    }
    #endif

    i = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i,
                     sizeof(i)) == -1) {
        upipe_err_va(upipe, "unable to set socket (%m)");
        close(fd);
        return -1;
    }

    if (family == AF_INET6) {
        if (bind_if_index
              && setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                     (void *)&bind_if_index, sizeof(bind_if_index)) < 0) {
            upipe_err(upipe, "couldn't set interface index");
            upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
            close(fd);
            return -1;
        }

        if (bind_addr.ss.ss_family != AF_UNSPEC) {
            #if !defined(__APPLE__) && !defined(__native_client__)
            if (IN6_IS_ADDR_MULTICAST(&bind_addr.sin6.sin6_addr)) {
                struct ipv6_mreq imr;
                union sockaddru bind_addr_any = bind_addr;
                bind_addr_any.sin6.sin6_addr = in6addr_any;

                if (bind(fd, &bind_addr_any.so,
                           sizeof(bind_addr_any)) < 0) {
                    upipe_err(upipe, "couldn't bind");
                    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
                    close(fd);
                    return -1;
                }

                imr.ipv6mr_multiaddr = bind_addr.sin6.sin6_addr;
                imr.ipv6mr_interface = bind_if_index;

                /* Join Multicast group without source filter */
                if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
                                 (char *)&imr, sizeof(struct ipv6_mreq)) < 0) {
                    upipe_err(upipe, "couldn't join multicast group");
                    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
                    close(fd);
                    return -1;
                }
            } else
            #endif
                goto normal_bind;
        }
    }
    else if (bind_addr.ss.ss_family != AF_UNSPEC) {
normal_bind:
        if (bind(fd, &bind_addr.so, sockaddr_len) < 0) {
            upipe_err(upipe, "couldn't bind");
            upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
            close(fd);
            return -1;
        }
    }

    if (!*use_tcp) {
        /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to
         * avoid packet loss caused by scheduling problems */
        i = 0x80000;
        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *) &i, sizeof(i)))
            upipe_warn(upipe, "fail to increase receive buffer");

        /* Join the multicast group if the socket is a multicast address */
        if (bind_addr.ss.ss_family == AF_INET
              && IN_MULTICAST(ntohl(bind_addr.sin.sin_addr.s_addr))) {
#ifndef __native_client__
            if (connect_addr.ss.ss_family != AF_UNSPEC) {
                /* Source-specific multicast */
                struct ip_mreq_source imr;
                imr.imr_multiaddr = bind_addr.sin.sin_addr;
                imr.imr_interface.s_addr = if_addr;
                imr.imr_sourceaddr = connect_addr.sin.sin_addr;
                if (bind_if_index) {
                    upipe_warn(upipe, "ignoring ifindex option in SSM");
                }

                if (setsockopt(fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
                            (char *)&imr, sizeof(struct ip_mreq_source)) < 0) {
                    upipe_err_va(upipe, "couldn't join multicast group (%m)");
                    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr,
                                 &connect_addr);
                    close(fd);
                    return -1;
                }
            } else if (bind_if_index) {
                /* Linux-specific interface-bound multicast */
                struct ip_mreqn imr;
                imr.imr_multiaddr = bind_addr.sin.sin_addr;
                imr.imr_address.s_addr = if_addr;
                imr.imr_ifindex = bind_if_index;

                if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                                 (char *)&imr, sizeof(struct ip_mreqn)) < 0) {
                    upipe_err_va(upipe, "couldn't join multicast group (%m)");
                    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr,
                                 &connect_addr);
                    close(fd);
                    return -1;
                }
            } else
#endif
            {
                /* Regular multicast */
                struct ip_mreq imr;
                imr.imr_multiaddr = bind_addr.sin.sin_addr;
                imr.imr_interface.s_addr = if_addr;

                if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                                 (char *)&imr, sizeof(struct ip_mreq)) < 0) {
                    upipe_err_va(upipe, "couldn't join multicast group (%m)");
                    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr,
                                 &connect_addr);
                    close(fd);
                    return -1;
                }
            }
#ifdef SO_BINDTODEVICE
            if (ifname) {
                /* linux specific, needs root or CAP_NET_RAW */
                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
                               ifname, strlen(ifname) + 1) < 0) {
                    upipe_err_va(upipe, "couldn't bind to device %s (%m)",
                                 ifname);
                    free(ifname);
                    close(fd);
                    return -1;
                }
                ubase_clean_str(&ifname);
            }
#endif
        }
    }

    if (connect_addr.ss.ss_family != AF_UNSPEC) {
        if (connect(fd, &connect_addr.so, sockaddr_len) < 0) {
            upipe_err_va(upipe, "cannot connect socket (%m)");
            upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
            close(fd);
            return -1;
        }

        if (!*use_tcp) {
            if (ttl) {
                if (family == AF_INET
                      && IN_MULTICAST(ntohl(connect_addr.sin.sin_addr.s_addr))) {
                    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
                                     (void *)&ttl, sizeof(ttl)) == -1) {
                        upipe_err_va(upipe, "couldn't set TTL (%m)");
                        upipe_udp_print_socket(upipe, "socket definition:", &bind_addr,
                                     &connect_addr);
                        close(fd);
                        return -1;
                    }
                }

                if (family == AF_INET6
                      && IN6_IS_ADDR_MULTICAST(&connect_addr.sin6.sin6_addr)) {
                    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                                     (void *)&ttl, sizeof(ttl)) == -1) {
                        upipe_err_va(upipe, "couldn't set TTL (%m)");
                        upipe_udp_print_socket(upipe, "socket definition:", &bind_addr,
                                     &connect_addr);
                        close(fd);
                        return -1;
                    }
                }
            }

            if (tos) {
                if (setsockopt(fd, IPPROTO_IP, IP_TOS,
                                 (void *)&tos, sizeof(tos)) == -1) {
                    upipe_err_va(upipe, "couldn't set TOS (%m)");
                    upipe_udp_print_socket(upipe, "socket definition:", &bind_addr,
                                 &connect_addr);
                    close(fd);
                    return -1;
                }
            }
        }
    } else if (*use_tcp) {
        /* Open in listen mode - wait for an incoming connection */
        int new_fd;
        if (listen(fd, 1) < 0) {
            upipe_err_va(upipe, "couldn't listen (%m)");
            upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
            close(fd);
            return -1;
        }

        while ((new_fd = accept(fd, NULL, NULL)) < 0) {
            if (errno != EINTR) {
                upipe_err_va(upipe, "couldn't accept (%m)");
                upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr);
                close(fd);
                return -1;
            }
        }
        close(fd);
        return new_fd;
    }

    return fd;
}
Example #17
0
/** @internal @This handles buffers once stripped from uref.
 *
 * @param upipe description structure of the pipe
 * @param buf buffer containing packet
 * @param size buffer size before padding
 * @param upump upump structure
 */
static bool upipe_avcdec_process_buf(struct upipe *upipe, uint8_t *buf,
                                    size_t size, struct upump *upump)
{
    int gotframe = 0, len;
    AVPacket avpkt;
    AVFrame *frame; 
    uint64_t framenum = 0;

    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    assert(upipe);

    /* init avcodec packed and attach input buffer */
    av_init_packet(&avpkt);
    avpkt.size = size;
    avpkt.data = buf;

    frame = upipe_avcdec->frame;

    switch (upipe_avcdec->context->codec->type) {
        case AVMEDIA_TYPE_VIDEO: {

            len = avcodec_decode_video2(upipe_avcdec->context, frame, &gotframe, &avpkt);
            if (len < 0) {
                upipe_warn(upipe, "Error while decoding frame");
            }

            /* output frame if any has been decoded */
            if (gotframe) {
                uref_pic_get_number(frame->opaque, &framenum);

                upipe_dbg_va(upipe, "%u\t - Picture decoded ! %dx%d - %u",
                        upipe_avcdec->counter, frame->width, frame->height, (uint64_t) framenum);

                upipe_avcdec_output_frame(upipe, frame, upump);
                return true;
            } else {
                return false;
            }
        }

        case AVMEDIA_TYPE_AUDIO: {
            len = avcodec_decode_audio4(upipe_avcdec->context, frame, &gotframe, &avpkt);
            if (len < 0) {
                upipe_warn(upipe, "Error while decoding frame");
            }

            /* output samples if any has been decoded */
            if (gotframe) {
                upipe_avcdec_output_audio(upipe, frame, upump);
                return true;
            } else {
                return false;
            }
        }

        default: {
            /* should never be here */
            upipe_err_va(upipe, "Unsupported media type (%d)",
                                    upipe_avcdec->context->codec->type);
            return false;
        }
    }
}
Example #18
0
/** @internal @This is called by avcodec when allocating a new frame
 * @param context current avcodec context
 * @param frame avframe handler entering avcodec black magic box
 */
static int upipe_avcdec_get_buffer(struct AVCodecContext *context, AVFrame *frame)
{
    struct upipe *upipe = context->opaque;
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    struct ubuf *ubuf_pic;
    int width_aligned, height_aligned, i;
    const struct upipe_av_plane *planes = NULL;
    size_t stride = 0;

    frame->opaque = uref_dup(upipe_avcdec->uref);

    uint64_t framenum = 0;
    uref_pic_get_number(frame->opaque, &framenum);

    upipe_dbg_va(upipe, "Allocating frame for %u (%p) - %ux%u",
                 framenum, frame->opaque, frame->width, frame->height);

    if (unlikely(!upipe_avcdec->pixfmt)) {
        upipe_avcdec->pixfmt = upipe_av_pixfmt_from_ubuf_mgr(upipe_avcdec->ubuf_mgr);
        if (unlikely(!upipe_avcdec->pixfmt)) {
            upipe_err_va(upipe, "frame format of ubuf manager not recognized");
            return 0;
        }
    }
    if (context->pix_fmt != *upipe_avcdec->pixfmt->pixfmt) {
        upipe_err_va(upipe, "frame format not compatible (%s != %s",
                                       av_get_pix_fmt_name(context->pix_fmt),
                            av_get_pix_fmt_name(*upipe_avcdec->pixfmt->pixfmt));
        return 0;
    }
    planes = upipe_avcdec->pixfmt->planes;

    /* direct rendering - allocate ubuf pic */
    if (upipe_avcdec->context->codec->capabilities & CODEC_CAP_DR1) {
        width_aligned = context->width;
        height_aligned = context->height;

        /* use avcodec width/height alignement, then resize pic */
        avcodec_align_dimensions(context, &width_aligned, &height_aligned);
        ubuf_pic = ubuf_pic_alloc(upipe_avcdec->ubuf_mgr, width_aligned, height_aligned);

        if (likely(ubuf_pic)) {
            ubuf_pic_resize(ubuf_pic, 0, 0, context->width, context->height);
            uref_attach_ubuf(frame->opaque, ubuf_pic);

            for (i=0; i < 4 && planes[i].chroma; i++) {
                ubuf_pic_plane_write(ubuf_pic, planes[i].chroma,
                        0, 0, -1, -1, &frame->data[i]);
                ubuf_pic_plane_size(ubuf_pic, planes[i].chroma, &stride,
                        NULL, NULL, NULL);
                frame->linesize[i] = stride;
            }

            frame->extended_data = frame->data;
            frame->type = FF_BUFFER_TYPE_USER;
            
            return 1; /* success */
        } else {
            upipe_dbg_va(upipe, "ubuf_pic_alloc(%d, %d) failed, fallback", width_aligned, height_aligned);
        }
    }

    /* default : DR failed or not available */
    return avcodec_default_get_buffer(context, frame);
}
Example #19
0
/** @internal @This asks to open the given device.
 *
 * @param upipe description structure of the pipe
 * @param path relative or absolute path of the file
 * @return an error code
 */
static int upipe_dveo_asi_sink_open(struct upipe *upipe)
{
#define BYPASS_MODE 1

    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);
    char path[20], sys[50], buf[20];
    memset(buf, 0, sizeof(buf));

    static const char dev_fmt[] = "/dev/asitx%u";
    static const char sys_fmt[] = "/sys/class/asi/asitx%u/%s";
    static const char dvbm_sys_fmt[] = "/sys/class/dvbm/%u/%s";

    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "timestamps");
    snprintf(buf, sizeof(buf), "%u\n", 2);
    if (util_write(sys, buf, sizeof(buf)) < 0) {
        upipe_err_va(upipe, "Couldn't set timestamp mode (%m)");
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "bufsize");
    snprintf(buf, sizeof(buf), "%u\n", 6*(188+8)); /* minimum is 1024 */
    if (util_write(sys, buf, sizeof(buf)) < 0) {
        upipe_err_va(upipe, "Couldn't set buffer size (%m)");
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "buffers");
    snprintf(buf, sizeof(buf), "%u\n", 500);
    if (util_write(sys, buf, sizeof(buf)) < 0) {
        upipe_err_va(upipe, "Couldn't set # of buffers (%m)");
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(path, sizeof(path), dev_fmt, upipe_dveo_asi_sink->card_idx);
    int fd = open(path, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
    if (unlikely(fd < 0)) {
        upipe_err_va(upipe, "can't open file %s (%m)", path);
        return UBASE_ERR_EXTERNAL;
    }

    snprintf(sys, sizeof(sys), dvbm_sys_fmt, upipe_dveo_asi_sink->card_idx, "bypass_mode");
    snprintf(buf, sizeof(buf), "%u", BYPASS_MODE);
    util_write(sys, buf, sizeof(buf)); /* Not all cards have this so don't fail */

    unsigned int cap;
    if (ioctl(fd, ASI_IOC_TXGETCAP, &cap) < 0) {
        upipe_err_va(upipe, "can't get tx caps (%m)");
        goto error;
    }

    unsigned long int bufsize;
    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "bufsize");
    if (util_strtoul(sys, &bufsize) < 0) {
        upipe_err(upipe, "Couldn't read buffer size");
        goto error;
    }

    unsigned long int mode;
    snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "mode");
    if (util_strtoul(sys, &mode) < 0) {
        upipe_err(upipe, "Couldn't read buffer size");
        goto error;
    }

    switch (mode) {
        case ASI_CTL_TX_MODE_MAKE204:
            upipe_dbg(upipe, "Appending 0x00 bytes to make 204 bytes packets");
        case ASI_CTL_TX_MODE_188:
        case ASI_CTL_TX_MODE_204:
            break;
        default:
            upipe_err_va(upipe, "Unknown TX mode %lu", mode);
            goto error;
    }

    unsigned long int clock_source = 0;
    if (cap & ASI_CAP_TX_SETCLKSRC) {
        snprintf(sys, sizeof(sys), sys_fmt, upipe_dveo_asi_sink->card_idx, "clock_source");
        if (util_strtoul(sys, &clock_source) < 0) {
            upipe_err(upipe, "Couldn't read clock source");
            goto error;
        }
    }

    switch (clock_source) {
        case ASI_CTL_TX_CLKSRC_ONBOARD:
            upipe_dbg(upipe, "Using onboard oscillator");
            break;
        case ASI_CTL_TX_CLKSRC_EXT:
            upipe_dbg(upipe, "Using external reference clock");
            break;
        case ASI_CTL_TX_CLKSRC_RX:
            upipe_dbg(upipe, "Using recovered receive clock");
            break;
        default:
            upipe_dbg(upipe, "Unknown clock source");
                break;
    }

    if (!(cap & ASI_CAP_TX_TIMESTAMPS)) {
        upipe_err(upipe, "Device does not support timestamps");
        goto error;
    }

    upipe_dveo_asi_sink->fd = fd;

    upipe_notice_va(upipe, "opening file %s", path);
    return UBASE_ERR_NONE;

error:
    close(fd);
    return UBASE_ERR_EXTERNAL;
}
Example #20
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;
}
Example #21
0
/** @internal @This configures a new codec context
 *
 * @param upipe description structure of the pipe
 * @param codec avcodec description structure
 * @param extradata pointer to extradata buffer
 * @param extradata_size extradata size
 * @return false if the buffer couldn't be accepted
 */
static bool upipe_avcdec_open_codec(struct upipe *upipe, AVCodec *codec,
                                    uint8_t *extradata, int extradata_size)
{
    AVCodecContext *context = NULL;
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    assert(upipe);

    /* close previously opened context */
    if (unlikely(upipe_avcdec->context)) {
        /* first send empty packet to flush retained frames */
        upipe_dbg(upipe, "flushing frames in decoder");
        while (upipe_avcdec_process_buf(upipe, NULL, 0, NULL));

        /* now close codec and free extradata if any */
        upipe_notice_va(upipe, "avcodec context (%s) closed (%d)",
                    upipe_avcdec->context->codec->name, upipe_avcdec->counter);
        avcodec_close(upipe_avcdec->context);
        if (upipe_avcdec->context->extradata_size > 0) {
            free(upipe_avcdec->context->extradata);
        }
        av_free(upipe_avcdec->context);
        upipe_avcdec->context = NULL;
        upipe_avcdec_store_flow_def(upipe, NULL);
    }

    /* just closing, that's all */
    if (!codec) {
        upipe_release(upipe);
        return false;
    }

    /* allocate and configure codec context */
    context = avcodec_alloc_context3(codec);
    if (unlikely(!context)) {
        upipe_throw_aerror(upipe);
        upipe_release(upipe);
        return false;
    }
    context->opaque = upipe;
    context->extradata = extradata;
    context->extradata_size = extradata_size;

    switch (codec->type) {
        case AVMEDIA_TYPE_VIDEO: {
            if (upipe_avcdec->lowres > codec->max_lowres) {
                upipe_warn_va(upipe, "Unsupported lowres (%d > %hhu), setting to %hhu",
                    upipe_avcdec->lowres, codec->max_lowres, codec->max_lowres);
                upipe_avcdec->lowres = codec->max_lowres;
            }

            context->get_buffer = upipe_avcdec_get_buffer;
            context->release_buffer = upipe_avcdec_release_buffer;
            context->flags |= CODEC_FLAG_EMU_EDGE;
            context->lowres = upipe_avcdec->lowres;
            context->skip_loop_filter = AVDISCARD_ALL;

            break;
        }
        case AVMEDIA_TYPE_AUDIO: {
            context->get_buffer = upipe_avcdec_get_buffer_audio;
            break;
        }
        default: {
            av_free(context);
            upipe_err_va(upipe, "Unsupported media type (%d)", codec->type);
            upipe_release(upipe);
            return false;
            break;
        }
    }

    /* open new context */
    if (unlikely(avcodec_open2(context, codec, NULL) < 0)) {
        upipe_warn(upipe, "could not open codec");
        av_free(context);
        upipe_release(upipe);
        return false;
    }

    upipe_avcdec->context = context;
    upipe_avcdec->counter = 0;
    upipe_notice_va(upipe, "codec %s (%s) %d opened", codec->name, 
            codec->long_name, codec->id);

    upipe_release(upipe);
    return true;
}
Example #22
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);
}
Example #23
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);
}
Example #24
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 bool upipe_s337_encaps_handle(struct upipe *upipe, struct uref *uref,
                                    struct upump **upump_p)
{
    struct upipe_s337_encaps *upipe_s337_encaps = upipe_s337_encaps_from_upipe(upipe);

    if (!upipe_s337_encaps->ubuf_mgr)
        return false;

    size_t block_size;
    if (!ubase_check(uref_block_size(uref, &block_size))) {
        upipe_err(upipe, "Couldn't read block size");
        uref_free(uref);
        return true;
    }

    struct ubuf *ubuf = ubuf_sound_alloc(upipe_s337_encaps->ubuf_mgr, A52_FRAME_SAMPLES);
    if (!ubuf)
        return false;

    if (block_size / 2 > A52_FRAME_SAMPLES - 4) {
        upipe_err_va(upipe, "AC-3 block size %zu too big", block_size);
        block_size = (A52_FRAME_SAMPLES - 4) * 2;
    }

    int32_t *out_data;
    ubuf_sound_write_int32_t(ubuf, 0, -1, &out_data, 1);

    /* Pa, Pb, Pc, Pd */
    out_data[0] = (S337_PREAMBLE_A1 << 24) | (S337_PREAMBLE_A2 << 16);
    out_data[1] = (S337_PREAMBLE_B1 << 24) | (S337_PREAMBLE_B2 << 16);
    out_data[2] = (S337_TYPE_A52 << 16) | (S337_MODE_16 << 21) |
        (S337_TYPE_A52_REP_RATE_FLAG << 24);
    out_data[3] = ((block_size * 8) & 0xffff) << 16;

    int offset = 0;
    uint8_t tmp = 0;
    while (block_size) {
        const uint8_t *buf;
        int size = block_size;

        if (!ubase_check(uref_block_read(uref, offset, &size, &buf)) || size == 0) {
            ubuf_sound_unmap(ubuf, 0, -1, 1);
            ubuf_free(ubuf);
            uref_free(uref);
            return true;
        }

        if (offset & 1) {
            out_data[4 + offset/2] = (tmp << 24) | (buf[0] << 16);
            buf++;
            offset++;
            block_size--;
            size--;
        }

        for (int i = 0; i < size/2; i++)
            out_data[4 + offset/2 + i] = (buf[2*i + 0] << 24) | (buf[2*i + 1] << 16);
        if (size & 1)
            tmp = buf[size-1];

        uref_block_unmap(uref, offset);

        block_size -= size;
        offset += size;
    }

    memset(&out_data[4 + offset/2], 0, 4 * (A52_FRAME_SAMPLES*2 - 4 - offset/2));

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

    uref_attach_ubuf(uref, ubuf);
    upipe_s337_encaps_output(upipe, uref, upump_p);
    return true;
}