Exemple #1
0
/** catch probes from probe_uref */
static int uref_catch(struct uprobe *uprobe, struct upipe *upipe,
                      int event, va_list args)
{
    if (event != UPROBE_PROBE_UREF)
        return uprobe_throw_next(uprobe, upipe, event, args);

    va_list args_copy;
    va_copy(args_copy, args);
    unsigned int signature = va_arg(args_copy, unsigned int);
    va_end(args_copy);
    if (signature != UPIPE_PROBE_UREF_SIGNATURE)
        return uprobe_throw_next(uprobe, upipe, event, args);

    if (upipe_source != NULL) {
        /* dump the pipeline before leaving */
        if (dump != NULL)
            upipe_dump_open(NULL, NULL, dump, NULL, upipe_source, NULL);

        /* release the source to exit */
        upipe_release(upipe_source);
        upipe_source = NULL;
        /* send demux output to /dev/null */
        upipe_set_output(upipe_split_output, upipe_null);
        upipe_release(upipe_split_output);
        upipe_split_output = NULL;
    } else {
        /* second (or after) frame, do not output them */
        upipe_set_output(upipe, upipe_null);
    }
    return UBASE_ERR_NONE;
}
Exemple #2
0
/** @internal @This catches events of the dec queue source.
 *
 * @param uprobe pointer to probe
 * @param upipe pointer to pipe throwing the event
 * @param event event thrown
 * @param args optional event-specific parameters
 * @return an error code
 */
static int upipe_glxplayer_catch_dec_qsrc(struct uprobe *uprobe,
                                          struct upipe *upipe,
                                          int event, va_list args)
{
    switch (event) {
        case UPROBE_SOURCE_END: {
            struct upipe_glxplayer *glxplayer =
                container_of(uprobe, struct upipe_glxplayer, uprobe_dec_qsrc_s);
            upipe_flush(glxplayer->upipe_glx_qsink);
            upipe_release(glxplayer->upipe_glx_qsink);
            return UBASE_ERR_NONE;
        }
        case UPROBE_NEED_OUTPUT: {
            struct upipe_glxplayer *glxplayer =
                container_of(uprobe, struct upipe_glxplayer, uprobe_dec_qsrc_s);
            struct upipe *avcdec = upipe_void_alloc_output(upipe,
                    glxplayer->upipe_avcdec_mgr,
                    uprobe_pfx_alloc_va(
                            uprobe_use(&glxplayer->uprobe_avcdec_s),
                        glxplayer->loglevel, "avcdec"));
            if (unlikely(avcdec == NULL))
                return UBASE_ERR_ALLOC;
            upipe_set_option(avcdec, "threads", "2");
            upipe_release(avcdec);
            return UBASE_ERR_NONE;
        }
        default:
            return uprobe_throw_next(uprobe, upipe, event, args);
    }
}
Exemple #3
0
/** @internal @This catches events of the qsrc of the glx (main) thread.
 *
 * @param uprobe pointer to probe
 * @param upipe pointer to pipe throwing the event
 * @param event event thrown
 * @param args optional event-specific parameters
 * @return an error code
 */
static int upipe_glxplayer_catch_glx_qsrc(struct uprobe *uprobe,
                                          struct upipe *upipe,
                                          int event, va_list args)
{
    switch (event) {
        case UPROBE_SOURCE_END: {
            struct upipe_glxplayer *glxplayer =
                container_of(uprobe, struct upipe_glxplayer,
                             uprobe_glx_qsrc_s);
            upipe_release(upipe);
            pthread_join(glxplayer->src_thread_id, NULL);
            if (glxplayer->trickp)
                upipe_release(glxplayer->upipe_trickp);
            free(glxplayer->uri);
            return UBASE_ERR_NONE;
        }
        case UPROBE_NEED_OUTPUT: {
            struct upipe_glxplayer *glxplayer =
                container_of(uprobe, struct upipe_glxplayer,
                             uprobe_glx_qsrc_s);
            struct upipe *trickp_pic;
            if (glxplayer->trickp) {
                glxplayer->upipe_trickp =
                    upipe_void_alloc(glxplayer->upipe_trickp_mgr,
                         uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                                          glxplayer->loglevel, "trickp"));
                if (unlikely(glxplayer->upipe_trickp == NULL))
                    return UBASE_ERR_ALLOC;
                upipe_attach_uclock(glxplayer->upipe_trickp);
                trickp_pic = upipe_void_alloc_output_sub(upipe,
                        glxplayer->upipe_trickp,
                        uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                                         glxplayer->loglevel, "trickp pic"));
                if (unlikely(trickp_pic == NULL))
                    return UBASE_ERR_ALLOC;
            } else
                trickp_pic = upipe;

            /* glx sink */
            struct upipe *glx_sink = upipe_void_alloc_output(trickp_pic,
                    glxplayer->upipe_glx_mgr,
                    uprobe_gl_sink_cube_alloc(
                         uprobe_pfx_alloc(
                             uprobe_use(&glxplayer->uprobe_glx_s),
                             glxplayer->loglevel, "glx")));
            if (glxplayer->trickp)
                upipe_release(trickp_pic);
            if (unlikely(glx_sink == NULL))
                return UBASE_ERR_ALLOC;
            upipe_glx_sink_init(glx_sink, 0, 0, 800, 480);
            upipe_attach_uclock(glx_sink);
            upipe_release(glx_sink);
            return UBASE_ERR_NONE;
        }
        default:
            return uprobe_throw_next(uprobe, upipe, event, args);
    }
}
Exemple #4
0
/** @internal @This catches events of the avcdec.
 *
 * @param uprobe pointer to probe
 * @param upipe pointer to pipe throwing the event
 * @param event event thrown
 * @param args optional event-specific parameters
 * @return an error code
 */
static int upipe_glxplayer_catch_avcdec(struct uprobe *uprobe,
                                        struct upipe *upipe,
                                        int event, va_list args)
{
    switch (event) {
        case UPROBE_NEED_OUTPUT: {
            struct upipe_glxplayer *glxplayer =
                container_of(uprobe, struct upipe_glxplayer, uprobe_avcdec_s);
            struct uref *flow_def = va_arg(args, struct uref *);
            struct upipe *deint =
                upipe_void_alloc_output(upipe,
                        glxplayer->upipe_filter_blend_mgr,
                        uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                                         glxplayer->loglevel, "deint"));
            if (unlikely(deint == NULL))
                return UBASE_ERR_ALLOC;

            struct uref *output_flow = uref_dup(flow_def);
            if (unlikely(output_flow == NULL))
                return UBASE_ERR_ALLOC;
            uref_pic_flow_clear_format(output_flow);
            if (unlikely(!ubase_check(uref_pic_flow_set_macropixel(output_flow, 1)) ||
                         !ubase_check(uref_pic_flow_set_planes(output_flow, 0)) ||
                         !ubase_check(uref_pic_flow_add_plane(output_flow, 1, 1, 3,
                                                  "r8g8b8")))) {
                uref_free(output_flow);
                return UBASE_ERR_ALLOC;
            }

            struct upipe *yuvrgb = upipe_flow_alloc_output(deint,
                    glxplayer->upipe_sws_mgr,
                    uprobe_pfx_alloc_va(uprobe_use(glxplayer->uprobe_logger),
                                        glxplayer->loglevel, "rgb"),
                    output_flow);
            assert(yuvrgb != NULL);
            uref_free(output_flow);
            upipe_release(deint);

            glxplayer->upipe_glx_qsink =
                upipe_qsink_alloc(glxplayer->upipe_qsink_mgr,
                    uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                    glxplayer->loglevel, "glx qsink"),
                    glxplayer->upipe_glx_qsrc);
            if (unlikely(glxplayer->upipe_glx_qsink == NULL))
                return UBASE_ERR_ALLOC;
            upipe_set_output(yuvrgb, glxplayer->upipe_glx_qsink);
            upipe_release(yuvrgb);
            return UBASE_ERR_NONE;
        }
        default:
            return uprobe_throw_next(uprobe, upipe, event, args);
    }
}
Exemple #5
0
/** @internal @This allocates a hls pipe.
 *
 * @param mgr management structure for this pipe type
 * @param uprobe structure used to raise events
 * @param signature signature of the pipe allocator
 * @param args optional arguments
 * @return pointer to allocated pipe, or NULL in case of failure
 */
static struct upipe *upipe_hls_alloc(struct upipe_mgr *mgr,
                                     struct uprobe *uprobe,
                                     uint32_t signature,
                                     va_list args)
{
    struct upipe *upipe =
        upipe_hls_alloc_void(mgr, uprobe, signature, args);
    if (unlikely(upipe == NULL))
        return NULL;

    struct upipe_hls *upipe_hls = upipe_hls_from_upipe(upipe);

    upipe_hls_init_urefcount(upipe);
    upipe_hls_init_urefcount_real(upipe);
    upipe_hls_init_probe_reader(upipe);
    upipe_hls_init_probe_master(upipe);
    upipe_hls_init_probe_null(upipe);
    upipe_hls_init_first_inner(upipe);
    upipe_hls_init_last_inner(upipe);
    upipe_hls_init_bin_input(upipe);
    upipe_hls_init_bin_output(upipe);
    upipe_hls->flow_def = NULL;
    upipe_hls->item = NULL;
    upipe_hls->sub_pipe_mgr = NULL;

    upipe_throw_ready(upipe);

    struct upipe *inner = NULL;
    struct upipe_mgr *upipe_m3u_reader_mgr = upipe_m3u_reader_mgr_alloc();
    if (unlikely(!upipe_m3u_reader_mgr)) {
        upipe_err(upipe, "fail to allocate m3u reader manager");
        upipe_release(upipe);
        return NULL;
    }

    inner = upipe_void_alloc(
        upipe_m3u_reader_mgr,
        uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_reader),
                         UPROBE_LOG_VERBOSE, "reader"));
    upipe_mgr_release(upipe_m3u_reader_mgr);
    if (unlikely(!inner)) {
        upipe_err(upipe, "fail to allocate m3u reader");
        upipe_release(upipe);
        return NULL;
    }
    upipe_hls_store_bin_input(upipe, inner);

    return upipe;
}
Exemple #6
0
/** @internal @This allocates a video blank pipe.
 *
 * @param mgr pointer to upipe manager
 * @param uprobe structure used to raise events
 * @param signature signature of the pipe allocator
 * @param args optional arguments
 * @return an allocated pipe
 */
static struct upipe *upipe_vblk_alloc(struct upipe_mgr *mgr,
                                      struct uprobe *uprobe,
                                      uint32_t signature, va_list args)
{
    struct uref *flow_def;
    struct upipe *upipe = upipe_vblk_alloc_flow(mgr, uprobe, signature, args,
                                                &flow_def);
    if (unlikely(!upipe)) {
        return NULL;
    }

    upipe_vblk_init_urefcount(upipe);
    upipe_vblk_init_output(upipe);
    upipe_vblk_init_flow_def(upipe);
    upipe_vblk_init_ubuf_mgr(upipe);

    struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe);
    upipe_vblk->ubuf = NULL;

    upipe_throw_ready(upipe);

    if (unlikely(!ubase_check(upipe_vblk_check_flow_def(upipe, flow_def)))) {
        uref_free(flow_def);
        upipe_release(upipe);
        return NULL;
    }

    upipe_vblk_store_flow_def(upipe, flow_def);

    return upipe;
}
/** @This is called when there is no external reference to the pipe anymore.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_wsrc_no_ref(struct upipe *upipe)
{
    struct upipe_wsrc *upipe_wsrc = upipe_wsrc_from_upipe(upipe);
    upipe_release(upipe_wsrc->source);
    upipe_wsrc->source = NULL;
    upipe_wsrc_clean_bin_output(upipe);
    urefcount_release(upipe_wsrc_to_urefcount_real(upipe_wsrc));
}
Exemple #8
0
/** @internal @This flushes all currently held buffers, and unblocks the
 * sources.
 *
 * @param upipe description structure of the pipe
 * @return an error code
 */
static int upipe_fsink_flush(struct upipe *upipe)
{
    if (upipe_fsink_flush_input(upipe)) {
        upipe_fsink_set_upump(upipe, NULL);
        /* All packets have been output, release again the pipe that has been
         * used in @ref upipe_fsink_input. */
        upipe_release(upipe);
    }
    return UBASE_ERR_NONE;
}
Exemple #9
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;
}
Exemple #10
0
/** @internal @This is called when the file descriptor can be written again.
 * Unblock the sink and unqueue all queued buffers.
 *
 * @param upump description structure of the watcher
 */
static void upipe_fsink_watcher(struct upump *upump)
{
    struct upipe *upipe = upump_get_opaque(upump, struct upipe *);
    upipe_fsink_set_upump(upipe, NULL);
    upipe_fsink_output_input(upipe);
    upipe_fsink_unblock_input(upipe);
    if (upipe_fsink_check_input(upipe)) {
        /* All packets have been output, release again the pipe that has been
         * used in @ref upipe_fsink_input. */
        upipe_release(upipe);
    }
}
Exemple #11
0
/** @internal @This handles inner reader pipe events.
 *
 * @param uprobe structure used to raise events
 * @param inner pointer to inner pipe
 * @param event event thrown
 * @param args optional arguments
 * @return an error code
 */
static int probe_reader(struct uprobe *uprobe, struct upipe *inner,
                        int event, va_list args)
{
    struct upipe_hls *upipe_hls = upipe_hls_from_probe_reader(uprobe);
    struct upipe *upipe = upipe_hls_to_upipe(upipe_hls);

    if (event >= UPROBE_LOCAL)
        return UBASE_ERR_NONE;

    if (event == UPROBE_NEED_OUTPUT) {
        struct uref *flow_format = va_arg(args, struct uref *);
        const char *def;
        UBASE_RETURN(uref_flow_get_def(flow_format, &def));

        struct uref *flow_format_dup = uref_dup(flow_format);
        if (unlikely(!flow_format_dup)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return UBASE_ERR_ALLOC;
        }
        upipe_hls_store_flow_def(upipe, flow_format_dup);

        if (!strcmp(def, "block.m3u.playlist.")) {
            struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc();
            struct upipe *output = upipe_void_alloc_output(
                inner, upipe_null_mgr,
                uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_null),
                                 UPROBE_LOG_VERBOSE, "null"));
            upipe_mgr_release(upipe_null_mgr);
            upipe_release(output);

            upipe_split_throw_update(upipe);
            return UBASE_ERR_NONE;
        }
        else if (!strcmp(def, "block.m3u.master.")) {
            struct upipe_mgr *upipe_hls_master_mgr =
                upipe_hls_master_mgr_alloc();
            UBASE_ALLOC_RETURN(upipe_hls_master_mgr);
            struct upipe *output = upipe_void_alloc_output(
                inner, upipe_hls_master_mgr,
                uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_master),
                                 UPROBE_LOG_VERBOSE, "master"));
            upipe_mgr_release(upipe_hls_master_mgr);
            UBASE_ALLOC_RETURN(output);
            upipe_hls_store_bin_output(upipe, output);
            return UBASE_ERR_NONE;
        }
        else
            upipe_warn_va(upipe, "unsupported flow format %s", def);
        return UBASE_ERR_INVALID;
    }

    return upipe_throw_proxy(upipe, inner, event, args);
}
Exemple #12
0
/** @internal @This catches events of the glx pipe.
 *
 * @param uprobe pointer to probe
 * @param upipe pointer to pipe throwing the event
 * @param event event thrown
 * @param args optional event-specific parameters
 * @return an error code
 */
static int upipe_glxplayer_catch_glx(struct uprobe *uprobe,
                                     struct upipe *upipe,
                                     int event, va_list args)
{
    switch (event) {
        case UPROBE_GLX_SINK_KEYPRESS: {
            struct upipe_glxplayer *glxplayer =
                container_of(uprobe, struct upipe_glxplayer,
                             uprobe_glx_s);
            unsigned int signature = va_arg(args, unsigned int);
            assert(signature == UPIPE_GLX_SINK_SIGNATURE);
            unsigned long key = va_arg(args, unsigned long);

            switch (key) {
                case 27:
                case 'q': {
                    upipe_notice_va(upipe, "exit key pressed (%d), exiting",
                                    key);
                    upipe_release(glxplayer->upipe_src_xfer);
                    upipe_mgr_release(glxplayer->src_xfer);
                    break;
                }
                case ' ': {
                    if (glxplayer->trickp) {
                        if ( (glxplayer->paused = !glxplayer->paused) ) {
                            upipe_notice(upipe, "Playback paused");
                            struct urational rate = { .num = 0, .den = 0 };
                            upipe_trickp_set_rate(glxplayer->upipe_trickp, rate);
                        } else {
                            upipe_notice(upipe, "Playback resumed");
                            struct urational rate = { .num = 1, .den = 1 };
                            upipe_trickp_set_rate(glxplayer->upipe_trickp, rate);
                        }
                    }
                    break;
                }
                default:
                    upipe_dbg_va(upipe, "key pressed (%d)", key);
                    break;
            }
            return UBASE_ERR_NONE;
        }
        case UPROBE_GLX_SINK_KEYRELEASE:
            return UBASE_ERR_NONE;
        default:
            break;
    }
    return uprobe_throw_next(uprobe, upipe, event, args);
}
Exemple #13
0
static int upipe_s337_encaps_check(struct upipe *upipe, struct uref *flow_format)
{
    if (flow_format != NULL)
        upipe_s337_encaps_store_flow_def(upipe, flow_format);

    bool was_buffered = !upipe_s337_encaps_check_input(upipe);
    upipe_s337_encaps_output_input(upipe);
    upipe_s337_encaps_unblock_input(upipe);
    if (was_buffered && upipe_s337_encaps_check_input(upipe)) {
        /* All packets have been output, release again the pipe that has been
         * used in @ref upipe_s337_encaps_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_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;
}
Exemple #15
0
/** @internal @This checks if the input may start.
 *
 * @param upipe description structure of the pipe
 * @param flow_format amended flow format
 * @return an error code
 */
static int upipe_filter_blend_check(struct upipe *upipe,
                                    struct uref *flow_format)
{
    struct upipe_filter_blend *upipe_filter_blend =
        upipe_filter_blend_from_upipe(upipe);
    if (flow_format != NULL)
        upipe_filter_blend_store_flow_def(upipe, flow_format);

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

    bool was_buffered = !upipe_filter_blend_check_input(upipe);
    upipe_filter_blend_output_input(upipe);
    upipe_filter_blend_unblock_input(upipe);
    if (was_buffered && upipe_filter_blend_check_input(upipe)) {
        /* All packets have been output, release again the pipe that has been
         * used in @ref upipe_filter_blend_input. */
        upipe_release(upipe);
    }
    return UBASE_ERR_NONE;
}
Exemple #16
0
/** @internal @This provides a ubuf_mgr request.
 *
 * @param upipe description structure of the pipe
 * @param flow_format amended flow format
 * @return an error code
 */
static int upipe_audiobar_check_ubuf_mgr(struct upipe *upipe,
                                         struct uref *flow_format)
{
    struct upipe_audiobar *upipe_audiobar = upipe_audiobar_from_upipe(upipe);
    if (flow_format == NULL)
        return UBASE_ERR_NONE;

    upipe_audiobar_store_flow_def(upipe, flow_format);
    UBASE_RETURN(uref_pic_flow_get_hsize(flow_format, &upipe_audiobar->hsize))
    UBASE_RETURN(uref_pic_flow_get_vsize(flow_format, &upipe_audiobar->vsize))
    upipe_audiobar->chan_width =
        upipe_audiobar->hsize / upipe_audiobar->channels;
    upipe_audiobar->chan_width -= upipe_audiobar->chan_width % 2;
    if (unlikely(upipe_audiobar->chan_width < 16)) {
        upipe_warn_va(upipe,
                "channel width is too small to have a separation (%"PRIu64")",
                upipe_audiobar->chan_width);
    }
    upipe_audiobar->sep_width = upipe_audiobar->chan_width / 4;
    upipe_audiobar->sep_width -= upipe_audiobar->sep_width % 4;
    upipe_audiobar->pad_width = upipe_audiobar->hsize -
        upipe_audiobar->chan_width * upipe_audiobar->channels;
    upipe_notice_va(upipe,
            "setting up chan %"PRIu64" sep %"PRIu64" pad %"PRIu64,
            upipe_audiobar->chan_width, upipe_audiobar->sep_width,
            upipe_audiobar->pad_width);

    bool was_buffered = !upipe_audiobar_check_input(upipe);
    upipe_audiobar_output_input(upipe);
    upipe_audiobar_unblock_input(upipe);
    if (was_buffered && upipe_audiobar_check_input(upipe)) {
        /* All packets have been output, release again the pipe that has been
         * used in @ref upipe_audiobar_input. */
        upipe_release(upipe);
    }
    return UBASE_ERR_NONE;
}
Exemple #17
0
/** @internal @This outputs the m3u.
 *
 * @param upipe description structure of the pipe
 * @param upump_p reference to source pump to block
 */
static void upipe_m3u_reader_output_all(struct upipe *upipe,
                                        struct upump **upump_p)
{
    struct upipe_m3u_reader *upipe_m3u_reader =
        upipe_m3u_reader_from_upipe(upipe);

    struct uref *flow_def = upipe_m3u_reader->current_flow_def;
    upipe_m3u_reader->current_flow_def = NULL;
    if (unlikely(!ubase_check(uref_flow_match_def(flow_def, M3U_FLOW_DEF)))) {
        upipe_err(upipe, "invalid m3u");
        uref_free(flow_def);
        return;
    }

    /* force new flow def */
    upipe_m3u_reader_store_flow_def(upipe, NULL);
    /* set output flow def */
    upipe_m3u_reader_store_flow_def(upipe, flow_def);

    /* output */
    struct uchain *uchain;
    bool first = true;
    upipe_use(upipe);
    while ((uchain = ulist_pop(&upipe_m3u_reader->items)) != NULL) {
        struct uref *uref = uref_from_uchain(uchain);

        if (first)
            uref_block_set_start(uref);
        first = false;

        if (ulist_empty(&upipe_m3u_reader->items))
            uref_block_set_end(uref);

        upipe_m3u_reader_output(upipe, uref, upump_p);
    }
    upipe_release(upipe);
}
Exemple #18
0
/** @This starts playing the given URI.
 *
 * @param glxplayer glxplayer context
 * @param upump_mgr upump manager of the main thread
 * @param uri URI to play
 * @param upipe_ts set to true to use Upipe's TS demux, false for libavformat
 * @return false in case of error
 */
static bool upipe_glxplayer_play(struct upipe_glxplayer *glxplayer,
                                 struct upump_mgr *upump_mgr, const char *uri,
                                 bool upipe_ts)
{
    struct upipe *upipe_src;
    uprobe_pthread_upump_mgr_set(glxplayer->uprobe_logger, upump_mgr);
    uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_FREEZE_UPUMP_MGR);
    if (!upipe_ts) {
        /* use avformat source (and internal demuxer) */
        struct upipe_mgr *upipe_avfsrc_mgr = upipe_avfsrc_mgr_alloc();
        if (unlikely(upipe_avfsrc_mgr == NULL))
            return false;

        upipe_src = upipe_void_alloc(upipe_avfsrc_mgr,
                    uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_selflow),
                                     glxplayer->loglevel, "avfsrc"));
        upipe_mgr_release(upipe_avfsrc_mgr);
        if (unlikely(upipe_src == NULL))
            return false;
        if (unlikely(!ubase_check(upipe_attach_uclock(upipe_src)) ||
                     !ubase_check(upipe_set_uri(upipe_src, uri)))) {
            upipe_release(upipe_src);
            return false;
        }
        glxplayer->trickp = true;
    } else {
        /* try file source */
        struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc();
        if (unlikely(upipe_fsrc_mgr == NULL))
            return false;

        upipe_src = upipe_void_alloc(upipe_fsrc_mgr,
                    uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s),
                                     glxplayer->loglevel, "fsrc"));
        upipe_mgr_release(upipe_fsrc_mgr);
        if (unlikely(upipe_src == NULL))
            return false;
        if (ubase_check(upipe_set_uri(upipe_src, uri))) {
            glxplayer->trickp = true;
        } else {
            upipe_release(upipe_src);
            glxplayer->trickp = false;

            /* try udp source */
            struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc();
            if (unlikely(upipe_udpsrc_mgr == NULL))
                return false;

            upipe_src = upipe_void_alloc(upipe_udpsrc_mgr,
                    uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s),
                                     glxplayer->loglevel, "udpsrc"));
            upipe_mgr_release(upipe_udpsrc_mgr);
            if (unlikely(upipe_src == NULL))
                return false;
            if (ubase_check(upipe_set_uri(upipe_src, uri))) {
                upipe_attach_uclock(upipe_src);
            } else {
                upipe_release(upipe_src);

                /* try http source */
                struct upipe_mgr *upipe_http_src_mgr =
                    upipe_http_src_mgr_alloc();
                if (unlikely(upipe_http_src_mgr == NULL))
                    return false;

                upipe_src = upipe_void_alloc(upipe_http_src_mgr,
                    uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s),
                                     glxplayer->loglevel, "httpsrc"));
                upipe_mgr_release(upipe_http_src_mgr);
                if (unlikely(upipe_src == NULL))
                    return false;
                if (!ubase_check(upipe_set_uri(upipe_src, uri))) {
                    upipe_release(upipe_src);
                    return false;
                }
            }
        }

        /* upipe-ts demuxer */
        struct upipe_mgr *upipe_ts_demux_mgr = upipe_ts_demux_mgr_alloc();
        if (unlikely(upipe_ts_demux_mgr == NULL)) {
            upipe_release(upipe_src);
            return false;
        }
        struct upipe_mgr *upipe_mpgvf_mgr = upipe_mpgvf_mgr_alloc();
        if (upipe_mpgvf_mgr != NULL) {
            upipe_ts_demux_mgr_set_mpgvf_mgr(upipe_ts_demux_mgr,
                                             upipe_mpgvf_mgr);
            upipe_mgr_release(upipe_mpgvf_mgr);
        }
        struct upipe_mgr *upipe_h264f_mgr = upipe_h264f_mgr_alloc();
        if (upipe_h264f_mgr != NULL) {
            upipe_ts_demux_mgr_set_h264f_mgr(upipe_ts_demux_mgr,
                                             upipe_h264f_mgr);
            upipe_mgr_release(upipe_h264f_mgr);
        }

        struct upipe *upipe_ts_demux =
            upipe_void_alloc_output(upipe_src, upipe_ts_demux_mgr,
                uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_selprog),
                                 glxplayer->loglevel, "ts demux"));
        if (unlikely(upipe_ts_demux == NULL)) {
            upipe_mgr_release(upipe_ts_demux_mgr);
            upipe_release(upipe_src);
            return false;
        }
        upipe_release(upipe_ts_demux);
        upipe_mgr_release(upipe_ts_demux_mgr);
    }

    if (!glxplayer->trickp)
        uprobe_dejitter_set(glxplayer->uprobe_dejitter, true, 0);

    /* prepare a queue source for the decoded video frames */
    uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_THAW_UPUMP_MGR);
    glxplayer->upipe_glx_qsrc = upipe_qsrc_alloc(glxplayer->upipe_qsrc_mgr,
            uprobe_pfx_alloc(
                    uprobe_use(&glxplayer->uprobe_glx_qsrc_s),
                glxplayer->loglevel, "glx qsrc"), GLX_QUEUE_LENGTH);
    if (unlikely(glxplayer->upipe_glx_qsrc == NULL)) {
        upipe_release(upipe_src);
        return false;
    }
    upipe_attach_upump_mgr(glxplayer->upipe_glx_qsrc);

    /* prepare to transfer the source to a new thread */
    glxplayer->src_xfer = upipe_xfer_mgr_alloc(XFER_QUEUE, XFER_POOL);
    if (unlikely(glxplayer->src_xfer == NULL)) {
        upipe_release(upipe_src);
        upipe_release(glxplayer->upipe_glx_qsrc);
        return false;
    }

    /* spawn a thread for the source */
    if (pthread_create(&glxplayer->src_thread_id, NULL,
                       upipe_glxplayer_source_thread, glxplayer)) {
        upipe_mgr_release(glxplayer->src_xfer);
        upipe_release(glxplayer->upipe_glx_qsrc);
        return false;
    }

    glxplayer->upipe_src_xfer = upipe_xfer_alloc(glxplayer->src_xfer,
                uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                                 glxplayer->loglevel, "source xfer"),
                upipe_src);
    if (unlikely(glxplayer->upipe_src_xfer == NULL)) {
        upipe_mgr_release(glxplayer->src_xfer);
        upipe_release(upipe_src);
        upipe_release(glxplayer->upipe_glx_qsrc);
        return false;
    }
    /* from now on upipe_src should not be accessed */
    upipe_attach_upump_mgr(glxplayer->upipe_src_xfer);

    glxplayer->upipe_ts = upipe_ts;
    glxplayer->uri = strdup(uri);
    return true;
}
/** @internal @This allocates a wsrc 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_wsrc_alloc(struct upipe_mgr *mgr,
                                       struct uprobe *uprobe,
                                       uint32_t signature, va_list args)
{
    struct upipe_wsrc_mgr *wsrc_mgr = upipe_wsrc_mgr_from_upipe_mgr(mgr);
    if (unlikely(signature != UPIPE_WSRC_SIGNATURE ||
                 wsrc_mgr->xfer_mgr == NULL))
        goto upipe_wsrc_alloc_err;
    struct upipe *remote = va_arg(args, struct upipe *);
    struct uprobe *uprobe_remote = va_arg(args, struct uprobe *);
    unsigned int queue_length = va_arg(args, unsigned int);
    assert(queue_length);
    if (unlikely(remote == NULL))
        goto upipe_wsrc_alloc_err2;

    struct upipe_wsrc *upipe_wsrc = malloc(sizeof(struct upipe_wsrc));
    if (unlikely(upipe_wsrc == NULL))
        goto upipe_wsrc_alloc_err2;

    struct upipe *upipe = upipe_wsrc_to_upipe(upipe_wsrc);
    upipe_init(upipe, mgr, uprobe);
    upipe_wsrc_init_urefcount(upipe);
    urefcount_init(upipe_wsrc_to_urefcount_real(upipe_wsrc), upipe_wsrc_free);
    upipe_wsrc_init_last_inner_probe(upipe);
    upipe_wsrc_init_bin_output(upipe);
    upipe_wsrc->source = NULL;

    uprobe_init(&upipe_wsrc->proxy_probe, upipe_wsrc_proxy_probe, NULL);
    upipe_wsrc->proxy_probe.refcount = upipe_wsrc_to_urefcount_real(upipe_wsrc);
    uprobe_init(&upipe_wsrc->qsrc_probe, upipe_wsrc_qsrc_probe,
                &upipe_wsrc->last_inner_probe);
    upipe_wsrc->qsrc_probe.refcount = upipe_wsrc_to_urefcount_real(upipe_wsrc);
    upipe_throw_ready(upipe);

    /* output queue */
    struct upipe *out_qsrc = upipe_qsrc_alloc(wsrc_mgr->qsrc_mgr,
            uprobe_pfx_alloc(uprobe_use(&upipe_wsrc->qsrc_probe),
                             UPROBE_LOG_VERBOSE, "out_qsrc"),
            queue_length > UINT8_MAX ? UINT8_MAX : queue_length);
    if (unlikely(out_qsrc == NULL))
        goto upipe_wsrc_alloc_err3;

    struct upipe *out_qsink = upipe_qsink_alloc(wsrc_mgr->qsink_mgr,
            uprobe_pfx_alloc(uprobe_remote, UPROBE_LOG_VERBOSE,
                             "out_qsink"),
            out_qsrc);
    if (unlikely(out_qsink == NULL)) {
        upipe_release(out_qsrc);
        goto upipe_wsrc_alloc_err3;
    }
    if (queue_length > UINT8_MAX)
        upipe_set_max_length(out_qsink, queue_length - UINT8_MAX);

    upipe_attach_upump_mgr(out_qsrc);
    upipe_wsrc_store_bin_output(upipe, out_qsrc);

    /* last remote */
    struct upipe *last_remote = upipe_use(remote);
    struct upipe *tmp;

    /* upipe_get_output is a control command and may trigger a need_upump_mgr
     * event */
    uprobe_throw(upipe->uprobe, NULL, UPROBE_FREEZE_UPUMP_MGR);
    while (ubase_check(upipe_get_output(last_remote, &tmp)) && tmp != NULL) {
        upipe_use(tmp);
        upipe_release(last_remote);
        last_remote = tmp;
    }
    uprobe_throw(upipe->uprobe, NULL, UPROBE_THAW_UPUMP_MGR);

    struct upipe *last_remote_xfer = upipe_xfer_alloc(wsrc_mgr->xfer_mgr,
            uprobe_pfx_alloc(uprobe_use(&upipe_wsrc->proxy_probe),
                             UPROBE_LOG_VERBOSE, "src_last_xfer"), last_remote);
    if (unlikely(last_remote_xfer == NULL)) {
        upipe_release(out_qsink);
        goto upipe_wsrc_alloc_err3;
    }
    upipe_attach_upump_mgr(last_remote_xfer);
    upipe_set_output(last_remote_xfer, out_qsink);
    upipe_release(out_qsink);

    /* remote */
    if (last_remote != remote) {
        upipe_wsrc->source = upipe_xfer_alloc(wsrc_mgr->xfer_mgr,
                uprobe_pfx_alloc(uprobe_use(&upipe_wsrc->proxy_probe),
                                 UPROBE_LOG_VERBOSE, "src_xfer"), remote);
        if (unlikely(upipe_wsrc->source == NULL)) {
            upipe_release(out_qsink);
            upipe_release(upipe);
            return NULL;
        }
        upipe_attach_upump_mgr(upipe_wsrc->source);
        upipe_release(last_remote_xfer);
    } else {
        upipe_wsrc->source = last_remote_xfer;
        upipe_release(remote);
    }
    return upipe;

upipe_wsrc_alloc_err3:
    upipe_release(remote);
    upipe_release(upipe);
    return NULL;

upipe_wsrc_alloc_err2:
    uprobe_release(uprobe_remote);
    upipe_release(remote);
upipe_wsrc_alloc_err:
    uprobe_release(uprobe);
    return NULL;
}
/** @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;
}
Exemple #21
0
/** @internal @This allocates a blank source 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_blksrc_alloc(struct upipe_mgr *mgr,
                                        struct uprobe *uprobe,
                                        uint32_t signature, va_list args)
{
    struct uref *flow_def;
    struct upipe *upipe = upipe_blksrc_alloc_flow(mgr, uprobe, signature, args,
                                                  &flow_def);
    if (unlikely(!upipe)) {
        return NULL;
    }

    struct upipe_blksrc *upipe_blksrc = upipe_blksrc_from_upipe(upipe);
    upipe_blksrc_init_urefcount(upipe);
    upipe_blksrc_init_urefcount_real(upipe);
    upipe_blksrc_init_src_probe(upipe);
    upipe_blksrc_init_blk_probe(upipe);
    upipe_blksrc_init_bin_input(upipe);
    upipe_blksrc_init_bin_output(upipe);
    upipe_blksrc->flow_def = flow_def;

    upipe_throw_ready(upipe);

    uint64_t duration = 0;
    if (ubase_check(uref_flow_match_def(flow_def, UREF_PIC_FLOW_DEF))) {
        struct urational fps;
        if (unlikely(!ubase_check(uref_pic_flow_get_fps(flow_def, &fps)))) {
            upipe_release(upipe);
            return NULL;
        }
        duration = (uint64_t)UCLOCK_FREQ * fps.den / fps.num;
    }
    else if (ubase_check(uref_flow_match_def(flow_def, UREF_SOUND_FLOW_DEF))) {
        uint64_t samples, rate;
        if (unlikely(!ubase_check(uref_sound_flow_get_samples(flow_def,
                                                              &samples))) ||
            unlikely(!ubase_check(uref_sound_flow_get_rate(flow_def,
                                                           &rate)))) {
            upipe_release(upipe);
            return NULL;
        }
        duration = samples * UCLOCK_FREQ / rate;
    }
    else {
        upipe_warn(upipe, "unsupported flow def");
        upipe_release(upipe);
        return NULL;
    }

    struct uref *src_flow_def = uref_void_flow_alloc_def(flow_def->mgr);
    if (unlikely(!src_flow_def)) {
        upipe_err(upipe, "fail to allocate source pipe flow def");
        upipe_release(upipe);
        return NULL;
    }

    if (unlikely(!ubase_check(uref_clock_set_duration(src_flow_def,
                                                      duration)))) {
        uref_free(src_flow_def);
        upipe_release(upipe);
        return NULL;
    }

    struct upipe_mgr *upipe_voidsrc_mgr = upipe_voidsrc_mgr_alloc();
    if (unlikely(!upipe_voidsrc_mgr)) {
        upipe_err(upipe, "fail to get void source manager");
        uref_free(src_flow_def);
        upipe_release(upipe);
        return NULL;
    }

    struct upipe *src =
        upipe_flow_alloc(upipe_voidsrc_mgr,
                         uprobe_pfx_alloc(
                            uprobe_use(&upipe_blksrc->src_probe),
                                       UPROBE_LOG_VERBOSE,
                                       "src"),
                         src_flow_def);
    upipe_mgr_release(upipe_voidsrc_mgr);
    uref_free(src_flow_def);
    if (unlikely(!src)) {
        upipe_err(upipe, "fail to allocate source pipe");
        upipe_release(upipe);
        return NULL;
    }

    upipe_blksrc_store_bin_input(upipe, src);

    struct upipe_mgr *upipe_blk_mgr = NULL;
    if (ubase_check(uref_flow_match_def(flow_def, UREF_PIC_FLOW_DEF))) {
        upipe_blk_mgr = upipe_vblk_mgr_alloc();
    }
    else if (ubase_check(uref_flow_match_def(flow_def, UREF_SOUND_FLOW_DEF))) {
        upipe_blk_mgr = upipe_ablk_mgr_alloc();
    }

    if (unlikely(!upipe_blk_mgr)) {
        upipe_err(upipe, "fail to get blank generator manager");
        upipe_release(upipe);
        return NULL;
    }

    struct upipe *blk =
        upipe_flow_alloc(upipe_blk_mgr,
                         uprobe_pfx_alloc(
                            uprobe_use(&upipe_blksrc->blk_probe),
                                       UPROBE_LOG_VERBOSE,
                                       "blk"),
                         flow_def);
    upipe_mgr_release(upipe_blk_mgr);
    if (unlikely(!blk)) {
        upipe_err(upipe, "fail to allocate blank generator pipe");
        upipe_release(upipe);
        return NULL;
    }

    upipe_blksrc_store_bin_output(upipe, blk);

    if (unlikely(!ubase_check(upipe_set_output(src, blk)))) {
        upipe_release(upipe);
        return NULL;
    }

    return upipe;
}
Exemple #22
0
int main(int argc, char **argv)
{
    int opt;

    /* parse options */
    while ((opt = getopt(argc, argv, "dqD:")) != -1) {
        switch (opt) {
            case 'd':
                if (loglevel > 0) loglevel--;
                break;
            case 'q':
                if (loglevel < UPROBE_LOG_ERROR) loglevel++;
                break;
            case 'D':
                dump = optarg;
                break;
            default:
                usage(argv[0]);
        }
    }
    if (optind >= argc - 1) {
        usage(argv[0]);
    }
    srcpath = argv[optind++];
    dstpath = argv[optind++];

    /* choose log fd */
    logstream = stderr;

    /* setup environnement */
    struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc();
    struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH,
                                                         umem_mgr, -1, -1);
    uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr,
                                                   0);

    struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL,
            UPUMP_BLOCKER_POOL);

    /* default probe */
    logger = uprobe_stdio_alloc(NULL, logstream, loglevel);
    assert(logger != NULL);
    logger = uprobe_uref_mgr_alloc(logger, uref_mgr);
    assert(logger != NULL);
    logger = uprobe_upump_mgr_alloc(logger, upump_mgr);
    assert(logger != NULL);
    logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH,
                                   UBUF_POOL_DEPTH);
    assert(logger != NULL);
    uref_mgr_release(uref_mgr);
    upump_mgr_release(upump_mgr);

    /* split probe */
    struct uprobe uprobe_catch;
    uprobe_init(&uprobe_catch, split_catch, uprobe_use(logger));

    /* other probes */
    uprobe_init(&uprobe_avcdec, avcdec_catch, uprobe_use(logger));
    uprobe_init(&uprobe_uref, uref_catch, uprobe_use(logger));

    /* upipe-av */
    upipe_av_init(true, uprobe_use(logger));

    /* global pipe managers */
    upipe_avcdec_mgr = upipe_avcdec_mgr_alloc();
    upipe_avcenc_mgr = upipe_avcenc_mgr_alloc();
    upipe_sws_mgr = upipe_sws_mgr_alloc();
    upipe_filter_blend_mgr = upipe_filter_blend_mgr_alloc();
    upipe_fsink_mgr = upipe_fsink_mgr_alloc();
    upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc();

    /* null */
    struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc();
    upipe_null = upipe_void_alloc(upipe_null_mgr,
            uprobe_pfx_alloc(uprobe_use(logger), loglevel, "null"));
    assert(upipe_null != NULL);
    upipe_mgr_release(upipe_null_mgr);

    /* file source */
    struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc();
    upipe_source = upipe_void_alloc(upipe_fsrc_mgr,
            uprobe_pfx_alloc(uprobe_use(logger), loglevel, "fsrc"));
    assert(upipe_source != NULL);
    upipe_mgr_release(upipe_fsrc_mgr);
    if (!ubase_check(upipe_set_uri(upipe_source, srcpath)))
        exit(EXIT_FAILURE);

    /* upipe-ts */
    struct upipe_mgr *upipe_ts_demux_mgr = upipe_ts_demux_mgr_alloc();
    struct upipe_mgr *upipe_autof_mgr = upipe_autof_mgr_alloc();
    upipe_ts_demux_mgr_set_autof_mgr(upipe_ts_demux_mgr, upipe_autof_mgr);
    upipe_mgr_release(upipe_autof_mgr);
    struct upipe *ts_demux = upipe_void_alloc_output(upipe_source,
            upipe_ts_demux_mgr,
            uprobe_pfx_alloc(
                uprobe_selflow_alloc(uprobe_use(logger),
                    uprobe_selflow_alloc(uprobe_use(logger), &uprobe_catch,
                        UPROBE_SELFLOW_PIC, "auto"),
                    UPROBE_SELFLOW_VOID, "auto"),
                 loglevel, "tsdemux"));
    assert(ts_demux != NULL);
    upipe_mgr_release(upipe_ts_demux_mgr);
    upipe_release(ts_demux);

    /* fire loop ! */
    upump_mgr_run(upump_mgr, NULL);

    /* release everyhing */
    upipe_release(upipe_source);
    upipe_release(upipe_split_output);
    upipe_release(upipe_null);
    uprobe_release(logger);
    uprobe_clean(&uprobe_catch);
    uprobe_clean(&uprobe_avcdec);
    uprobe_clean(&uprobe_uref);

    upipe_mgr_release(upipe_avcdec_mgr);
    upipe_mgr_release(upipe_avcenc_mgr);
    upipe_mgr_release(upipe_sws_mgr);
    upipe_mgr_release(upipe_filter_blend_mgr);
    upipe_mgr_release(upipe_fsink_mgr);
    upipe_mgr_release(upipe_probe_uref_mgr);

    udict_mgr_release(udict_mgr);
    umem_mgr_release(umem_mgr);

    upipe_av_clean();

    return 0;
}
Exemple #23
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;
}
int main(int argc, char *argv[])
{
    assert(argc >= 2);
    nb_files = argc - 1;
    files = argv + 1;

    struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL,
            UPUMP_BLOCKER_POOL);
    assert(upump_mgr != NULL);

    struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc();
    assert(umem_mgr != NULL);
    struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH,
                                                         umem_mgr, -1, -1);
    assert(udict_mgr != NULL);
    struct uref_mgr *uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr,
                                                   0);
    /* main probe */
    struct uprobe *logger =
        uprobe_stdio_alloc(NULL, stderr, UPROBE_LOG_VERBOSE);
    assert(logger != NULL);
    logger = uprobe_uref_mgr_alloc(logger, uref_mgr);
    assert(logger != NULL);
    logger = uprobe_upump_mgr_alloc(logger, upump_mgr);
    assert(logger != NULL);
    logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH,
                                   UBUF_POOL_DEPTH);
    assert(logger != NULL);

    /* file source */
    struct uprobe uprobe_fsrc;
    uprobe_init(&uprobe_fsrc, catch_fsrc, uprobe_use(logger));
    struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc();
    assert(upipe_fsrc_mgr != NULL);
    struct upipe *upipe_fsrc = upipe_void_alloc(upipe_fsrc_mgr,
            uprobe_pfx_alloc(uprobe_use(&uprobe_fsrc),
                             UPROBE_LOG_DEBUG, "file source"));
    assert(upipe_fsrc != NULL);
    upipe_mgr_release(upipe_fsrc_mgr);
    ubase_assert(upipe_set_uri(upipe_fsrc, files[current]));

    /* m3u reader */
    struct upipe_mgr *upipe_m3u_reader_mgr = upipe_m3u_reader_mgr_alloc();
    assert(upipe_m3u_reader_mgr != NULL);
    struct upipe *upipe_m3u_reader = upipe_void_alloc_output(
        upipe_fsrc, upipe_m3u_reader_mgr,
        uprobe_pfx_alloc(uprobe_use(logger),
                         UPROBE_LOG_VERBOSE, "m3u reader"));
    upipe_mgr_release(upipe_m3u_reader_mgr);
    assert(upipe_m3u_reader != NULL);

    struct uprobe uprobe_uref;
    uprobe_init(&uprobe_uref, catch_uref, uprobe_use(logger));
    struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc();
    assert(upipe_probe_uref_mgr != NULL);
    struct upipe *upipe_probe_uref = upipe_void_chain_output(
        upipe_m3u_reader, upipe_probe_uref_mgr,
        uprobe_pfx_alloc(uprobe_use(&uprobe_uref),
                         UPROBE_LOG_DEBUG, "probe uref"));
    upipe_mgr_release(upipe_probe_uref_mgr);
    assert(upipe_probe_uref != NULL);

    /* null output */
    struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc();
    assert(upipe_null_mgr != NULL);
    struct upipe *upipe_null = upipe_void_chain_output(
        upipe_probe_uref, upipe_null_mgr,
        uprobe_pfx_alloc(uprobe_use(logger),
                         UPROBE_LOG_DEBUG, "null"));
    upipe_mgr_release(upipe_null_mgr);
    assert(upipe_null != NULL);
    upipe_release(upipe_null);

    /* run main loop */
    upump_mgr_run(upump_mgr, NULL);

    /* release */
    upipe_release(upipe_fsrc);
    upump_mgr_release(upump_mgr);
    uref_mgr_release(uref_mgr);
    udict_mgr_release(udict_mgr);
    umem_mgr_release(umem_mgr);
    uprobe_clean(&uprobe_fsrc);
    uprobe_clean(&uprobe_uref);
    uprobe_release(logger);
    return 0;
}
Exemple #25
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;
}
Exemple #26
0
/** @internal @This allocates a wsink 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_wsink_alloc(struct upipe_mgr *mgr,
                                       struct uprobe *uprobe,
                                       uint32_t signature, va_list args)
{
    struct upipe_wsink_mgr *wsink_mgr = upipe_wsink_mgr_from_upipe_mgr(mgr);
    if (unlikely(signature != UPIPE_WSINK_SIGNATURE ||
                 wsink_mgr->xfer_mgr == NULL))
        goto upipe_wsink_alloc_err;
    struct upipe *remote = va_arg(args, struct upipe *);
    struct uprobe *uprobe_remote = va_arg(args, struct uprobe *);
    unsigned int queue_length = va_arg(args, unsigned int);
    assert(queue_length);
    if (unlikely(remote == NULL))
        goto upipe_wsink_alloc_err2;

    struct upipe_wsink *upipe_wsink = malloc(sizeof(struct upipe_wsink));
    if (unlikely(upipe_wsink == NULL))
        goto upipe_wsink_alloc_err2;

    struct upipe *upipe = upipe_wsink_to_upipe(upipe_wsink);
    upipe_init(upipe, mgr, uprobe);
    upipe_wsink_init_urefcount(upipe);
    urefcount_init(upipe_wsink_to_urefcount_real(upipe_wsink),
                   upipe_wsink_free);
    upipe_wsink_init_bin_input(upipe);

    uprobe_init(&upipe_wsink->proxy_probe, upipe_wsink_proxy_probe, NULL);
    upipe_wsink->proxy_probe.refcount =
        upipe_wsink_to_urefcount_real(upipe_wsink);
    uprobe_init(&upipe_wsink->in_qsrc_probe, upipe_wsink_in_qsrc_probe,
                uprobe_remote);
    upipe_wsink->in_qsrc_probe.refcount =
        upipe_wsink_to_urefcount_real(upipe_wsink);
    upipe_throw_ready(upipe);

    /* remote */
    upipe_use(remote);
    struct upipe *remote_xfer = upipe_xfer_alloc(wsink_mgr->xfer_mgr,
            uprobe_pfx_alloc(uprobe_use(&upipe_wsink->proxy_probe),
                             UPROBE_LOG_VERBOSE, "sink_xfer"), remote);
    if (unlikely(remote_xfer == NULL)) {
        upipe_release(remote);
        upipe_release(upipe);
        return NULL;
    }
    upipe_attach_upump_mgr(remote_xfer);

    /* input queue */
    struct upipe *in_qsrc = upipe_qsrc_alloc(wsink_mgr->qsrc_mgr,
            uprobe_pfx_alloc(
                uprobe_use(&upipe_wsink->in_qsrc_probe),
                UPROBE_LOG_VERBOSE, "in_qsrc"),
            queue_length > UINT8_MAX ? UINT8_MAX : queue_length);
    if (unlikely(in_qsrc == NULL))
        goto upipe_wsink_alloc_err3;

    struct upipe *in_qsink = upipe_qsink_alloc(wsink_mgr->qsink_mgr,
            uprobe_pfx_alloc(uprobe_use(&upipe_wsink->proxy_probe),
                             UPROBE_LOG_VERBOSE, "in_qsink"),
            in_qsrc);
    if (unlikely(in_qsink == NULL))
        goto upipe_wsink_alloc_err3;
    upipe_wsink_store_bin_input(upipe, in_qsink);
    if (queue_length > UINT8_MAX)
        upipe_set_max_length(upipe_wsink->in_qsink, queue_length - UINT8_MAX);

    struct upipe *in_qsrc_xfer = upipe_xfer_alloc(wsink_mgr->xfer_mgr,
            uprobe_pfx_alloc(uprobe_use(&upipe_wsink->proxy_probe),
                             UPROBE_LOG_VERBOSE, "in_qsrc_xfer"),
            in_qsrc);
    if (unlikely(in_qsrc_xfer == NULL))
        goto upipe_wsink_alloc_err3;
    upipe_set_output(in_qsrc_xfer, remote);
    upipe_attach_upump_mgr(in_qsrc_xfer);
    upipe_release(remote);
    upipe_release(remote_xfer);
    upipe_release(in_qsrc_xfer);
    return upipe;

upipe_wsink_alloc_err3:
    upipe_release(remote);
    upipe_release(remote_xfer);
    upipe_release(upipe);
    return NULL;

upipe_wsink_alloc_err2:
    upipe_release(remote);
upipe_wsink_alloc_err:
    uprobe_release(uprobe);
    return NULL;
}
Exemple #27
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;
}
Exemple #28
0
/** @internal @This catches events of the video output of the demux.
 *
 * @param uprobe pointer to probe
 * @param upipe pointer to pipe throwing the event
 * @param event event thrown
 * @param args optional event-specific parameters
 * @return an error code
 */
static int upipe_glxplayer_catch_demux_output(struct uprobe *uprobe,
                                              struct upipe *upipe,
                                              int event, va_list args)
{
    struct upipe_glxplayer *glxplayer =
        container_of(uprobe, struct upipe_glxplayer, uprobe_demux_output_s);
    switch (event) {
        case UPROBE_NEED_OUTPUT: {
            struct uref *flow_def = va_arg(args, struct uref *);
            const char *def = "(none)";
            if (!ubase_check(uref_flow_get_def(flow_def, &def)) ||
                ubase_ncmp(def, "block.")) {
                upipe_warn_va(upipe, "flow def %s is not supported", def);
                return UBASE_ERR_UNHANDLED;
            }

            upipe_dbg_va(upipe, "add flow %s", def);

            /* prepare a queue to deport avcodec to a new thread */
            uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_FREEZE_UPUMP_MGR);
            struct upipe *upipe_dec_qsrc =
                upipe_qsrc_alloc(glxplayer->upipe_qsrc_mgr,
                    uprobe_pfx_alloc_va(uprobe_use(&glxplayer->uprobe_dec_qsrc_s),
                                              glxplayer->loglevel, "dec qsrc"),
                    DEC_QUEUE_LENGTH);
            if (unlikely(upipe_dec_qsrc == NULL)) {
                return UBASE_ERR_ALLOC;
            }
            uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_THAW_UPUMP_MGR);

            glxplayer->upipe_dec_qsink =
                upipe_qsink_alloc(glxplayer->upipe_qsink_mgr,
                    uprobe_pfx_alloc_va(
                            uprobe_use(glxplayer->uprobe_logger),
                            glxplayer->loglevel, "dec qsink"),
                    upipe_dec_qsrc);
            if (unlikely(glxplayer->upipe_dec_qsink == NULL)) {
                upipe_release(upipe_dec_qsrc);
                return UBASE_ERR_ALLOC;
            }
            upipe_set_output(upipe, glxplayer->upipe_dec_qsink);

            /* prepare to transfer the queue source */
            glxplayer->dec_xfer = upipe_xfer_mgr_alloc(XFER_QUEUE, XFER_POOL);
            if (unlikely(glxplayer->dec_xfer == NULL)) {
                upipe_release(upipe_dec_qsrc);
                return UBASE_ERR_ALLOC;
            }

            /* spawn a thread for the decoder */
            if (pthread_create(&glxplayer->dec_thread_id, NULL,
                               upipe_glxplayer_dec_thread, glxplayer)) {
                upipe_mgr_release(glxplayer->dec_xfer);
                upipe_release(upipe_dec_qsrc);
                return UBASE_ERR_ALLOC;
            }

            glxplayer->upipe_dec_qsrc_handle =
                upipe_xfer_alloc(glxplayer->dec_xfer,
                    uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                                     glxplayer->loglevel, "dec qsrc xfer"),
                    upipe_dec_qsrc);
            if (unlikely(glxplayer->upipe_dec_qsrc_handle == NULL)) {
                upipe_mgr_release(glxplayer->dec_xfer);
                upipe_release(upipe_dec_qsrc);
                return UBASE_ERR_ALLOC;
            }
            upipe_attach_upump_mgr(glxplayer->upipe_dec_qsrc_handle);
            upipe_set_output(glxplayer->upipe_dec_qsink, glxplayer->upipe_dec_qsrc_handle);
            return UBASE_ERR_NONE;
        }
        case UPROBE_SOURCE_END: {
            upipe_flush(glxplayer->upipe_dec_qsink);
            upipe_release(glxplayer->upipe_dec_qsink);
            glxplayer->upipe_dec_qsink = NULL;

            /* set dec_qsrc output to null */
            struct upipe *null = upipe_void_alloc(glxplayer->upipe_null_mgr,
                    uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger),
                                     glxplayer->loglevel, "dec qsrc null"));
            if (likely(null != NULL)) {
                upipe_set_output(glxplayer->upipe_dec_qsrc_handle, null);
                upipe_release(null);
            }
            upipe_release(glxplayer->upipe_dec_qsrc_handle);
            return UBASE_ERR_NONE;
        }
        default:
            return uprobe_throw_next(uprobe, upipe, event, args);
    }
}