Пример #1
0
/** @internal @This prints socket characteristics for debug purposes
 *
 * @param upipe description structure of the pipe
 * @param text descriptive text
 * @param bind bind sockaddr union
 * @param connect connect sockaddr union
 */
static void upipe_udp_print_socket(struct upipe *upipe, const char *text, union sockaddru *bind,
                         union sockaddru *connect)
{
    if (bind->ss.ss_family == AF_INET) {
        upipe_dbg_va(upipe, "%s bind:%s:%u", text,
                     inet_ntoa(bind->sin.sin_addr), ntohs(bind->sin.sin_port));
    } else if (bind->ss.ss_family == AF_INET6) {
        char buf[INET6_ADDRSTRLEN];
        upipe_dbg_va(upipe, "%s bind:[%s]:%u", text,
                     inet_ntop(AF_INET6, &bind->sin6.sin6_addr, buf,
                               sizeof(buf)),
                     ntohs(bind->sin6.sin6_port));
    }

    if (connect->ss.ss_family == AF_INET) {
        upipe_dbg_va(upipe, "%s connect:%s:%u", text,
                     inet_ntoa(connect->sin.sin_addr),
                     ntohs(connect->sin.sin_port));
    } else if (connect->ss.ss_family == AF_INET6) {
        char buf[INET6_ADDRSTRLEN];
        upipe_dbg_va(upipe, "%s connect:[%s]:%u", text,
                     inet_ntop(AF_INET6, &connect->sin6.sin6_addr, buf,
                               sizeof(buf)),
                     ntohs(connect->sin6.sin6_port));
    }
}
Пример #2
0
/** @internal @This handles urefs (data & flows).
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump pump that generated the buffer
 */
static void upipe_multicat_probe_input(struct upipe *upipe, struct uref *uref,
                                      struct upump *upump)
{
    struct upipe_multicat_probe *upipe_multicat_probe = upipe_multicat_probe_from_upipe(upipe);
    const char *def;

    if (unlikely(uref_flow_get_def(uref, &def))) {
        upipe_dbg_va(upipe, "flow definition %s", def);
        upipe_multicat_probe_store_flow_def(upipe, uref);
        return;
    }

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

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

    return _upipe_multicat_probe_input(upipe, uref, upump);
}
Пример #3
0
/** @internal @This frees all resources allocated.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_skip_free(struct upipe *upipe)
{
    struct upipe_skip *upipe_skip = upipe_skip_from_upipe(upipe);
    upipe_dbg_va(upipe, "releasing pipe %p", upipe);
    upipe_throw_dead(upipe);

    upipe_skip_clean_output(upipe);

    upipe_clean(upipe);
    free(upipe_skip);
}
Пример #4
0
/** @internal @This frees all resources allocated.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_rtpd_free(struct upipe *upipe)
{
    struct upipe_rtpd *upipe_rtpd = upipe_rtpd_from_upipe(upipe);
    upipe_dbg_va(upipe, "releasing pipe %p", upipe);
    upipe_throw_dead(upipe);

    uref_free(upipe_rtpd->flow_def_input);
    upipe_rtpd_clean_output(upipe);
    upipe_rtpd_clean_urefcount(upipe);
    upipe_rtpd_free_void(upipe);
}
Пример #5
0
/** @internal @This checks and parses a line of a m3u file.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param uref pointer to uref carrying the line to parse
 * @return an error code
 */
static int upipe_m3u_reader_process_line(struct upipe *upipe,
                                         struct uref *flow_def,
                                         struct uref *uref)
{
    static const struct {
        const char *pfx;
        int (*cb)(struct upipe *, struct uref *, const char *);
    } ext_cb[] = {
        { "#EXTM3U", upipe_m3u_reader_process_m3u },
        { "#EXT-X-VERSION:", upipe_m3u_reader_process_version },
        { "#EXT-X-TARGETDURATION:", upipe_m3u_reader_process_target_duration },
        { "#EXT-X-PLAYLIST-TYPE:", upipe_m3u_reader_process_playlist_type },
        { "#EXTINF:", upipe_m3u_reader_process_extinf },
        { "#EXT-X-BYTERANGE:", upipe_m3u_reader_process_byte_range },
        { "#EXT-X-MEDIA:", upipe_m3u_reader_process_media },
        { "#EXT-X-STREAM-INF:", upipe_m3u_reader_ext_x_stream_inf },
        { "#EXT-X-MEDIA-SEQUENCE:", upipe_m3u_reader_ext_x_media_sequence },
        { "#EXT-X-ENDLIST", upipe_m3u_reader_ext_x_endlist },
        { "#EXT-X-KEY:", upipe_m3u_reader_key },
    };

    size_t block_size;
    UBASE_RETURN(uref_block_size(uref, &block_size));

    uint8_t buffer[block_size + 1];
    memset(buffer, 0, sizeof (buffer));
    UBASE_RETURN(uref_block_extract(uref, 0, block_size, buffer));

    char *line = (char *)buffer;
    /* remove end of line */
    if (strlen(line) && line[strlen(line) - 1] == '\n') {
        line[strlen(line) - 1] = '\0';
        if (strlen(line) && line[strlen(line) - 1] == '\r')
            line[strlen(line) - 1] = '\0';
    }

    if (!strlen(line))
        return UBASE_ERR_NONE;

    if (*line == '#') {
        for (unsigned i = 0; i < UBASE_ARRAY_SIZE(ext_cb); i++) {
            if (strncmp(line, ext_cb[i].pfx, strlen(ext_cb[i].pfx)))
                continue;

            return ext_cb[i].cb(upipe, flow_def,
                                line + strlen(ext_cb[i].pfx));
        }
        upipe_dbg_va(upipe, "ignore `%s'", line);
        return UBASE_ERR_NONE;
    }

    return upipe_m3u_reader_process_uri(upipe, flow_def, line);
}
Пример #6
0
/** @hidden */
static int upipe_burst_throw_update(struct upipe *upipe, bool empty)
{
    struct upipe_burst *upipe_burst = upipe_burst_from_upipe(upipe);

    if (unlikely(upipe_burst->empty == empty))
        return UBASE_ERR_NONE;
    upipe_burst->empty = empty;

    upipe_dbg_va(upipe, "throw update %s", empty ? "empty" : "not empty");
    return upipe_throw(upipe, UPROBE_BURST_UPDATE, UPIPE_BURST_SIGNATURE,
                       empty);
}
Пример #7
0
static void keyhandler(struct upipe *upipe, unsigned long key)
{
    switch (key) {
        case 27:
        case 'q': {
            upipe_notice_va(upipe, "exit key pressed (%d), exiting", key);
            exit(0);
        }
        default:
            upipe_dbg_va(upipe, "key pressed (%d)", key);
            break;
    }
}
Пример #8
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);
}
Пример #9
0
/** @internal @This checks and parses a "#EXT-X-VERSION" 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_version(struct upipe *upipe,
                                            struct uref *flow_def,
                                            const char *line)
{
    UBASE_RETURN(uref_flow_match_def(flow_def, M3U_FLOW_DEF));

    char *endptr;
    unsigned long int version = strtoul(line, &endptr, 10);
    if (line == endptr || *endptr != '\0' || version > UINT8_MAX) {
        upipe_warn_va(upipe, "invalid version %s", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "version: %u", version);
    return uref_m3u_flow_set_version(flow_def, version);
}
Пример #10
0
/** @internal @This checks and parses a "#EXT-X-MEDIA-SEQUENCE" tag.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param line the trailing characters of the line
 * @return an error code
 */
static int upipe_m3u_reader_ext_x_media_sequence(struct upipe *upipe,
                                                 struct uref *flow_def,
                                                 const char *line)
{
    const char *def;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def));
    if (strcmp(def, M3U_FLOW_DEF) && strcmp(def, PLAYLIST_FLOW_DEF))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, PLAYLIST_FLOW_DEF));

    char *endptr;
    uint64_t media_sequence = strtoull(line, &endptr, 10);
    if (endptr == line || strlen(endptr)) {
        upipe_warn_va(upipe, "invalid media sequence %s", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "media sequence %"PRIu64, media_sequence);
    return uref_m3u_playlist_flow_set_media_sequence(flow_def, media_sequence);
}
Пример #11
0
/** @internal @This handles input uref.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump upump structure
 */
static void upipe_avcdec_input(struct upipe *upipe, struct uref *uref,
                              struct upump *upump)
{
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    if (upipe_avcdec->uref_mgr == NULL) {
        upipe_throw_need_uref_mgr(upipe);
        if (unlikely(upipe_avcdec->uref_mgr == NULL)) {
            uref_free(uref);
            return;
        }
    }

    const char *def = NULL;
    if (unlikely(uref_flow_get_def(uref, &def))) {
        if (unlikely(ubase_ncmp(def, EXPECTED_FLOW))) {
            upipe_throw_flow_def_error(upipe, uref);
            uref_free(uref);
            _upipe_avcdec_set_codec(upipe, NULL, NULL, 0);
            return;
        }

        upipe_dbg_va(upipe, "flow definition %s", def);
        def += strlen(EXPECTED_FLOW);
        _upipe_avcdec_set_codec(upipe, def, NULL, 0);
        uref_free(uref);
        return;
    }

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

    if (unlikely(!uref->ubuf)) {
        upipe_warn(upipe, "uref has no ubuf, dropping");
        uref_free(uref);
        return;
    }

    upipe_avcdec_input_packet(upipe, uref, upump);
}
Пример #12
0
/** @internal @This checks and parses a "#EXT-X-TARGETDURATION" tag.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param line the trailing characters of the line
 * @return an error code
 */
static int upipe_m3u_reader_process_target_duration(struct upipe *upipe,
                                                    struct uref *flow_def,
                                                    const char *line)
{
    const char *def;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def));
    if (strcmp(def, M3U_FLOW_DEF) && strcmp(def, PLAYLIST_FLOW_DEF))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, PLAYLIST_FLOW_DEF));

    const char *endptr;
    uint64_t duration;
    UBASE_RETURN(duration_to_uclock(line, &endptr, &duration));
    if (line == endptr || strlen(endptr)) {
        upipe_warn_va(upipe, "invalid target duration %s", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "target duration: %"PRIu64, duration);
    return uref_m3u_playlist_flow_set_target_duration(flow_def, duration);
}
Пример #13
0
/** helper phony pipe */
static void test_input(struct upipe *upipe, struct uref *uref,
                       struct upump **upump_p)
{
    struct x264_test *x264_test = x264_test_from_upipe(upipe);
    uint64_t pts = 0, dts = 0;
    if (uref->udict != NULL) {
        udict_dump(uref->udict, upipe->uprobe);
    }
    if (!ubase_check(uref_clock_get_pts_prog(uref, &pts))) {
        upipe_warn(upipe, "received packet with no pts");
    }
    if (!ubase_check(uref_clock_get_dts_prog(uref, &dts))) {
        upipe_warn(upipe, "received packet with no dts");
    }
    upipe_dbg_va(upipe, "received pic %d, pts: %"PRIu64" , dts: %"PRIu64,
                 x264_test->counter, pts, dts);
    x264_test->counter++;

    uref_free(uref);
}
Пример #14
0
/** @This sets the low resolution parameter, if supported by codec.
 * If some codec is already used, it is re-opened.
 *
 * @param upipe description structure of the pipe
 * @param lowres lowres parameter (0=disabled)
 * @return false in case of error
 */
static bool _upipe_avcdec_set_lowres(struct upipe *upipe, int lowres)
{
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    const char *codec_def;
    bool ret = true;

    if (lowres < 0) {
        upipe_warn_va(upipe, "Invalid lowres parameter (%d)", lowres);
        return false;
    }
    upipe_avcdec->lowres = lowres;
    upipe_dbg_va(upipe, "Requesting lowres %d", lowres);

    if (upipe_avcdec->context && upipe_avcdec->context->codec) {
        codec_def = upipe_av_to_flow_def(upipe_avcdec->context->codec->id);
        ret = _upipe_avcdec_set_codec(upipe, codec_def, upipe_avcdec->context->extradata,
                                upipe_avcdec->context->extradata_size);
    }
    return ret;
}
Пример #15
0
/** @internal @This copies extradata
 *
 * @param upipe description structure of the pipe
 * @param extradata pointer to extradata buffer
 * @param size extradata size
 * @return false if the buffer couldn't be accepted
 */
static uint8_t *upipe_avcdec_copy_extradata(struct upipe *upipe,
                                            const uint8_t *extradata, int size)
{
    uint8_t *buf;
    if (!extradata || size <= 0) {
        return NULL;
    }

    buf = malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
    if (!buf) {
        upipe_throw_aerror(upipe);
        return NULL;
    }

    memset(buf+size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
    memcpy(buf, extradata, size);

    upipe_dbg_va(upipe, "Received extradata (%d bytes)", size);
    return buf;
}
Пример #16
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump pump that generated the buffer
 */
static void upipe_skip_input(struct upipe *upipe, struct uref *uref,
                               struct upump *upump)
{
    struct upipe_skip *upipe_skip = upipe_skip_from_upipe(upipe);
    const char *def;

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

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

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

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

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

    upipe_skip_input_block(upipe, uref, upump);
}
Пример #17
0
/** @internal @This checks and parses a "#EXT-X-PLAYLIST-TYPE" tag.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param line the trailing characters of the line
 * @return an error code
 */
static int upipe_m3u_reader_process_playlist_type(struct upipe *upipe,
                                                  struct uref *flow_def,
                                                  const char *line)
{
    const char *def;
    UBASE_RETURN(uref_flow_get_def(flow_def, &def));
    if (strcmp(def, M3U_FLOW_DEF) && strcmp(def, PLAYLIST_FLOW_DEF))
        return UBASE_ERR_INVALID;
    UBASE_RETURN(uref_flow_set_def(flow_def, PLAYLIST_FLOW_DEF));

    static const char *types[] = { "VOD", "EVENT" };
    const char *type = NULL;
    for (unsigned i = 0; !type && i < UBASE_ARRAY_SIZE(types); i++)
        if (!strcmp(line, types[i]))
            type = types[i];
    if (unlikely(type == NULL)) {
        upipe_warn_va(upipe, "invalid playlist type `%s'", line);
        return UBASE_ERR_INVALID;
    }
    upipe_dbg_va(upipe, "playlist type %s", type);
    return uref_m3u_playlist_flow_set_type(flow_def, type);
}
Пример #18
0
/** @internal @This is called by avcodec when releasing a frame
 * @param context current avcodec context
 * @param frame avframe handler released by avcodec black magic box
 */
static void upipe_avcdec_release_buffer(struct AVCodecContext *context, AVFrame *frame)
{
    struct upipe *upipe = context->opaque;
    struct uref *uref = frame->opaque;
    const struct upipe_av_plane *planes = NULL;
    int i;

    uint64_t framenum = 0;
    uref_pic_get_number(uref, &framenum);

    upipe_dbg_va(upipe, "Releasing frame %u (%p)", (uint64_t) framenum, uref);

    if (likely(uref->ubuf)) {
        planes = upipe_avcdec_from_upipe(upipe)->pixfmt->planes;
        for (i=0; i < 4 && planes[i].chroma; i++) {
            ubuf_pic_plane_unmap(uref->ubuf, planes[i].chroma, 0, 0, -1, -1);
            frame->data[i] = NULL;
        }
    } else {
        avcodec_default_release_buffer(context, frame);
    }
    uref_free(uref);
}
Пример #19
0
/** @internal @This is called by avcodec when allocating a new audio buffer
 * Used with audio decoders.
 * @param context current avcodec context
 * @param frame avframe handler entering avcodec black magic box
 */
static int upipe_avcdec_get_buffer_audio(struct AVCodecContext *context, AVFrame *frame)
{
    struct upipe *upipe = context->opaque;
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    struct ubuf *ubuf_samples;
    uint8_t *buf;
    int size;

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

    /* direct rendering - allocate ubuf for audio */
    if (upipe_avcdec->context->codec->capabilities & CODEC_CAP_DR1) {
        
        ubuf_samples = ubuf_block_alloc(upipe_avcdec->ubuf_mgr,
                    av_samples_get_buffer_size(NULL, context->channels,
                        frame->nb_samples, context->sample_fmt, 1));

        if (likely(ubuf_samples)) {
            ubuf_block_write(ubuf_samples, 0, &size, &buf);
            uref_attach_ubuf(frame->opaque, ubuf_samples);

            av_samples_fill_arrays(frame->data, frame->linesize, buf,
                    context->channels, frame->nb_samples, context->sample_fmt, 1);

            frame->extended_data = frame->data;
            frame->type = FF_BUFFER_TYPE_USER;
            
            return 1; /* success */
        } else {
            upipe_dbg_va(upipe, "ubuf allocation failed, fallback");
        }
    }

    /* default : DR failed or not available */
    return avcodec_default_get_buffer(context, frame);
}
Пример #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;
}
Пример #21
0
/** @internal @This handles packets.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump upump structure
 */
static void upipe_avcdec_input_packet(struct upipe *upipe, struct uref *uref,
                              struct upump *upump)
{
    uint8_t *inbuf;
    size_t insize = 0;

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

    if (upipe_avcdec->upump_av_deal) { /* pending open_codec callback */
        upipe_dbg(upipe, "Received packet while open_codec pending");
        if (upump) {
            upump_mgr_sink_block(upump->mgr);
            upump_mgr_use(upump->mgr);
            upipe_avcdec->saved_upump_mgr = upump->mgr;
        }
        if (upipe_avcdec->saved_uref) {
            upipe_warn(upipe, "Dropping previously saved packet !");
            uref_free(upipe_avcdec->saved_uref);
        }
        upipe_avcdec->saved_uref = uref;
        return;
    } else if (upipe_avcdec->saved_uref) {
        upipe_dbg(upipe, "Processing previously saved packet");
        struct uref *prev_uref = upipe_avcdec->saved_uref;
        upipe_avcdec->saved_uref = NULL;
        /* Not a typo, using the current upump here */
        upipe_avcdec_input_packet(upipe, prev_uref, upump); 
    }

    if (!upipe_avcdec->context) {
        uref_free(uref);
        upipe_warn(upipe, "Received packet but decoder is not initialized");
        return;
    }

    /* avcodec input buffer needs to be at least 4-byte aligned and
       FF_INPUT_BUFFER_PADDING_SIZE larger than actual input size.
       Thus, extract ubuf content in a properly allocated buffer.
       Padding must be zeroed. */
    uref_block_size(uref, &insize);
    if (unlikely(!insize)) {
        upipe_warn(upipe, "Received packet with size 0, dropping");
        uref_free(uref);
        return;
    }

    upipe_dbg_va(upipe, "Received packet %u - size : %u", upipe_avcdec->counter, insize);
    inbuf = malloc(insize + FF_INPUT_BUFFER_PADDING_SIZE);
    if (unlikely(!inbuf)) {
        upipe_throw_aerror(upipe);
        return;
    }
    memset(inbuf, 0, insize + FF_INPUT_BUFFER_PADDING_SIZE);
    uref_block_extract(uref, 0, insize, inbuf); 
    ubuf_free(uref_detach_ubuf(uref));

    uref_pic_set_number(uref, upipe_avcdec->counter);

    /* Track current uref in pipe structure - required for buffer allocation
     * in upipe_avcdec_get_buffer */
    upipe_avcdec->uref = uref;

    upipe_avcdec_process_buf(upipe, inbuf, insize, upump);

    free(inbuf);
    uref_free(uref);
    upipe_avcdec->counter++;
}
Пример #22
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;
        }
    }
}
Пример #23
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);
}
Пример #24
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);
}
Пример #25
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);
    }
}
Пример #26
0
/** @internal @This is called back to fill NaCl audio buffer.
 * Please note that this function runs in a different thread.
 *
 * @param sample_buffer buffer to fill
 * @param buffer_size size of the buffer in octets
 * @param latency how long before the audio data is to be presented
 * @param user_data opaque pointing to the pipe
 */
static void upipe_nacl_audio_worker(void *sample_buffer, uint32_t buffer_size,
                                    PP_TimeDelta latency, void *user_data)
{
    struct upipe *upipe = (struct upipe *)user_data;
    struct upipe_nacl_audio *upipe_nacl_audio =
        upipe_nacl_audio_from_upipe(upipe);
    uint64_t next_pts = UINT64_MAX;

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

    uint32_t frames = buffer_size / 4;

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

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

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

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

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

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