Beispiel #1
0
static bool upipe_dveo_asi_sink_add_header(struct upipe *upipe, struct uref *uref,
    uint64_t pts)
{
    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);

    uint64_t hdr_size;
    if (!ubase_check(uref_block_get_header_size(uref, &hdr_size)))
        hdr_size = 0;

    if (hdr_size != 0)
        return false;

    /* alloc header */
    struct ubuf *header = ubuf_block_alloc(uref->ubuf->mgr, 8);
    if (unlikely(!header)) {
        return true;
    }

    /* 63-bits timestamp */
    union {
        uint8_t timestamp[8];
        uint64_t pts;
    } timestamp;

    timestamp.pts = pts;
    if (upipe_dveo_asi_sink->first_timestamp) {
        upipe_dveo_asi_sink->first_timestamp = false;
        // FIXME: set the counter in an empty packet, and account for latency
        timestamp.pts |= 1LLU << 63; /* Set MSB = Set the counter */
    }

    /* write header, 64 bits little-endian :
     * https://github.com/kierank/dveo-linux-master/blob/450e4b9e4292c2f71acd4d3d2e0a0cd0879d473a/doc/ASI/features.txt#L62 */
    int size = 8;
    uint8_t *header_write_ptr;
    if (!ubase_check(ubuf_block_write(header, 0, &size, &header_write_ptr))) {
        upipe_err(upipe, "could not write header");
        ubuf_free(header);
        return true;
    }
    memcpy(header_write_ptr, timestamp.timestamp, 8);
    uref_block_unmap(uref, 0);

    /* append payload (current ubuf) to header to form segmented ubuf */
    struct ubuf *payload = uref_detach_ubuf(uref);
    if (unlikely(!ubase_check(ubuf_block_append(header, payload)))) {
        upipe_warn(upipe, "could not append payload to header");
        ubuf_free(header);
        ubuf_free(payload);
        return true;
    }
    uref_attach_ubuf(uref, header);
    uref_block_set_header_size(uref, 8);

    return false;
}
Beispiel #2
0
/** @internal @This receives data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_telxf_input(struct upipe *upipe, struct uref *uref,
                              struct upump **upump_p)
{
    struct upipe_telxf *upipe_telxf = upipe_telxf_from_upipe(upipe);
    size_t uref_size;
    if (!ubase_check(uref_block_size(uref, &uref_size)) || !uref_size) {
        uref_free(uref);
        return;
    }
    bool end = ubase_check(uref_block_get_end(uref));

    if (ubase_check(uref_block_get_start(uref))) {
        if (upipe_telxf->next_uref != NULL)
            upipe_telxf_work(upipe, upump_p);

        upipe_telxf->next_uref = uref;
        upipe_telxf->next_uref_size = uref_size;
    } else if (likely(upipe_telxf->next_uref != NULL)) {
        struct ubuf *ubuf = uref_detach_ubuf(uref);
        uref_free(uref);
        if (unlikely(!ubase_check(uref_block_append(upipe_telxf->next_uref,
                                                    ubuf)))) {
            ubuf_free(ubuf);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }
        upipe_telxf->next_uref_size += uref_size;
    } else {
        uref_free(uref);
        return;
    }

    if (end)
        upipe_telxf_work(upipe, upump_p);
}
Beispiel #3
0
/** @internal @This sets the reference picture.
 *
 * @param upipe description structure of the pipe
 * @param uref picture buffer
 * @return an error code
 */
static int upipe_vblk_set_pic_real(struct upipe *upipe, struct uref *uref)
{
    struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe);
    if (upipe_vblk->ubuf)
        ubuf_free(upipe_vblk->ubuf);
    upipe_vblk->ubuf = uref->ubuf;
    uref->ubuf = NULL;
    uref_free(uref);
    return UBASE_ERR_NONE;
}
Beispiel #4
0
ZEND_METHOD (Msghdr, __destruct)
{
	int rc;
	zval **hdr = 0;
	char *ptr;

	if (zend_hash_find (Z_OBJPROP_P (getThis ()), "__ptr", sizeof("__ptr"), (void **) &hdr) == FAILURE)
		return;
	if ((ptr = Z_STRVAL_PP (hdr)) && (ptr = * (char **) ptr)) {
		ubuf_free (ptr);
	}
}
Beispiel #5
0
/** @internal @This frees an audio blank pipe.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_ablk_free(struct upipe *upipe)
{
    struct upipe_ablk *upipe_ablk = upipe_ablk_from_upipe(upipe);

    upipe_throw_dead(upipe);

    if (upipe_ablk->ubuf)
        ubuf_free(upipe_ablk->ubuf);
    upipe_ablk_clean_flow_def(upipe);
    upipe_ablk_clean_ubuf_mgr(upipe);
    upipe_ablk_clean_output(upipe);
    upipe_ablk_clean_urefcount(upipe);
    upipe_ablk_free_flow(upipe);
}
Beispiel #6
0
/** @internal @This receives data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_agg_input(struct upipe *upipe, struct uref *uref,
                            struct upump **upump_p)
{
    struct upipe_agg *upipe_agg = upipe_agg_from_upipe(upipe);
    size_t size = 0;
    const size_t output_size = upipe_agg->output_size;

    uref_block_size(uref, &size);

    /* check for invalid or too large size */
    if (unlikely(size == 0 || size > output_size)) {
        upipe_warn_va(upipe,
            "received packet of invalid size: %zu (output_size == %zu)", size, output_size);
        uref_free(uref);
        return;
    }

    /* flush if incoming packet makes aggregated overflow */
    if (upipe_agg->size + size > output_size) {
        upipe_agg_output(upipe, upipe_agg->aggregated, upump_p);
        upipe_agg->aggregated = NULL;
    }

    /* keep or attach incoming packet */
    if (unlikely(!upipe_agg->aggregated)) {
        upipe_agg->aggregated = uref;
        upipe_agg->size = size;
    } else {
        struct ubuf *append = uref_detach_ubuf(uref);
        uref_free(uref);
        if (unlikely(!ubase_check(uref_block_append(upipe_agg->aggregated,
                                                    append)))) {
            upipe_warn(upipe, "error appending packet");
            ubuf_free(append);
            return;
        };
        upipe_agg->size += size;
    }

    /* anticipate next packet size and flush now if necessary */
    if (upipe_agg->input_size)
        size = upipe_agg->input_size;
    if (unlikely(upipe_agg->size + size > output_size)) {
        upipe_agg_output(upipe, upipe_agg->aggregated, upump_p);
        upipe_agg->aggregated = NULL;
        upipe_agg->size = 0;
    }
}
Beispiel #7
0
static VALUE rb_sp_send (VALUE self, VALUE eid, VALUE msg)
{
	int _eid = FIX2INT (eid);
	int rc;
	VALUE rb_hdr = 0;
	char *hdr = 0;
	char *ubuf = ubuf_alloc (RSTRING (msg)->len);

	memcpy (ubuf, RSTRING (msg)->ptr, ubuf_len (ubuf));

	/* How can i checking the valid rb_values, f*****g the ruby extension here
	 */
	if ((rb_hdr = rb_iv_get (msg, "@hdr")) != 4) {
		Data_Get_Struct (rb_hdr, char, hdr);
		if (hdr)
			ubufctl (hdr, SCOPY, ubuf);
	}
	if ((rc = sp_send (_eid, ubuf)))
		ubuf_free (ubuf);
	return INT2FIX (rc);
}
/** @internal @This takes the payload of a TS packet, checks if it may
 * contain part of a PES header, and outputs it.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_ts_pesd_input(struct upipe *upipe, struct uref *uref,
                                struct upump **upump_p)
{
    struct upipe_ts_pesd *upipe_ts_pesd = upipe_ts_pesd_from_upipe(upipe);
    size_t uref_size;
    if (unlikely(!ubase_check(uref_block_size(uref, &uref_size)))) {
        upipe_warn(upipe, "invalid PES chunk");
        uref_free(uref);
        return;
    }

    if (ubase_check(uref_block_get_start(uref))) {
        if (unlikely(upipe_ts_pesd->next_uref != NULL)) {
            upipe_warn(upipe, "truncated PES header");
            uref_free(upipe_ts_pesd->next_uref);
        }
        upipe_ts_pesd->next_uref = uref;
        upipe_ts_pesd->next_uref_size = uref_size;
        upipe_ts_pesd_decaps(upipe, upump_p);

    } else if (upipe_ts_pesd->next_uref != NULL) {
        struct ubuf *ubuf = uref_detach_ubuf(uref);
        uref_free(uref);
        if (unlikely(!ubase_check(uref_block_append(upipe_ts_pesd->next_uref,
                                                    ubuf)))) {
            ubuf_free(ubuf);
            upipe_ts_pesd_flush(upipe);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }
        upipe_ts_pesd->next_uref_size += uref_size;
        upipe_ts_pesd_decaps(upipe, upump_p);
    } else if (likely(upipe_ts_pesd->acquired)) {
        upipe_ts_pesd->next_uref = uref;
        upipe_ts_pesd->next_uref_size += uref_size;
        upipe_ts_pesd_check_output(upipe, upump_p);
    } else
        uref_free(uref);
}
Beispiel #9
0
static void xclient (const char *pf)
{
	int sfd, i;
	int64_t nbytes;
	char buf[1024] = {};
	char *ubuf;
	char host[1024] = {};

	sprintf (host, "%s%s", pf, "://127.0.0.1:18897");
	randstr (buf, 1024);
	BUG_ON ( (sfd = xconnect (host) ) < 0);
	for (i = 0; i < cnt; i++) {
		nbytes = rand() % 1024;
		ubuf = ubuf_alloc (nbytes);
		memcpy (ubuf, buf, nbytes);
		BUG_ON (0 != xsend (sfd, ubuf) );
		BUG_ON (0 != xrecv (sfd, &ubuf) );
		DEBUG_OFF ("%d recv response", sfd);
		assert (memcmp (ubuf, buf, nbytes) == 0);
		ubuf_free (ubuf);
	}
	xclose (sfd);
}
Beispiel #10
0
/** @internal @This sets the input flow def.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the flow format to set
 * @return an error code
 */
static int upipe_vblk_set_flow_def(struct upipe *upipe,
                                   struct uref *flow_def)
{
    struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe);

    if (!ubase_check(uref_flow_match_def(flow_def, UREF_VOID_FLOW_DEF)) &&
        !ubase_check(upipe_vblk_check_flow_def(upipe, flow_def)))
        return UBASE_ERR_INVALID;

    struct uref *input_flow_def = uref_dup(flow_def);
    if (unlikely(!input_flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return UBASE_ERR_ALLOC;
    }
    upipe_vblk_store_flow_def_input(upipe, input_flow_def);

    if (ubase_check(uref_flow_match_def(flow_def, UREF_VOID_FLOW_DEF)))
        return UBASE_ERR_NONE;

    uint64_t hsize = 0, vsize = 0;
    UBASE_RETURN(uref_pic_flow_get_hsize(flow_def, &hsize));
    UBASE_RETURN(uref_pic_flow_get_vsize(flow_def, &vsize));

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

    struct urational sar;
    uref_pic_flow_clear_format(flow_def_dup);
    uref_pic_flow_copy_format(flow_def_dup, flow_def);
    uref_pic_flow_set_hsize(flow_def_dup, hsize);
    uref_pic_flow_set_vsize(flow_def_dup, vsize);
    if (likely(ubase_check(uref_pic_flow_get_sar(flow_def, &sar)))) {
        uref_pic_flow_set_sar(flow_def_dup, sar);
    } else {
        uref_pic_flow_delete_sar(flow_def_dup);
    }
    bool overscan;
    if (likely(ubase_check(uref_pic_flow_get_overscan(flow_def, &overscan)))) {
        uref_pic_flow_set_overscan(flow_def_dup, overscan);
    } else {
        uref_pic_flow_delete_overscan(flow_def_dup);
    }
    if (likely(ubase_check(uref_pic_get_progressive(flow_def)))) {
        uref_pic_set_progressive(flow_def_dup);
    } else {
        uref_pic_delete_progressive(flow_def_dup);
    }
    upipe_vblk_store_flow_def(upipe, flow_def_dup);

    if (upipe_vblk->ubuf) {
        ubuf_free(upipe_vblk->ubuf);
        upipe_vblk->ubuf = NULL;
    }

    if (upipe_vblk->ubuf_mgr &&
        !ubase_check(ubuf_mgr_check(upipe_vblk->ubuf_mgr, flow_def_dup))) {
        ubuf_mgr_release(upipe_vblk->ubuf_mgr);
        upipe_vblk->ubuf_mgr = NULL;
    }

    return UBASE_ERR_NONE;
}
Beispiel #11
0
static void upipe_rtp_h264_output_nalu(struct upipe *upipe,
                                       uint8_t nalu,
                                       struct uref *uref,
                                       struct upump **upump_p)
{
    size_t size = 0;
    if (unlikely(!ubase_check(uref_block_size(uref, &size)))) {
        upipe_err(upipe, "fail to get block size");
        return;
    }

    bool split = size > RTP_SPLIT_SIZE;
    uint32_t fragment = 0;

    while (size) {
        bool last_fragment = size <= RTP_SPLIT_SIZE;
        size_t split_size = last_fragment ? size : RTP_SPLIT_SIZE;
        uint8_t hdr[2] = { nalu, 0 };
        size_t hdr_size = 1;

        if (split) {
            if (!fragment)
                hdr[1] = FU_START;
            else if (last_fragment)
                hdr[1] = FU_END;
            hdr[1] |= NALU_TYPE(hdr[0]);

            hdr[0] = NALU_F(hdr[0]) | NALU_NRI(hdr[0]) | FU_A;
            hdr_size++;
        }

        struct uref *next = NULL;
        if (!last_fragment) {
            next = uref_block_split(uref, split_size);
            if (unlikely(next == NULL)) {
                upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
                return;
            }
        }

        /* FIXME should require a ubuf_mgr */
        struct ubuf *header =
                ubuf_block_alloc(uref->ubuf->mgr, hdr_size * sizeof (hdr[0]));
        if (unlikely(header == NULL)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(uref);
            uref_free(next);
            return;
        }

        uint8_t *buf = NULL;
        int buf_size = hdr_size;
        ubuf_block_write(header, 0, &buf_size, &buf);
        memcpy(buf, hdr, hdr_size * sizeof (hdr[0]));
        ubuf_block_unmap(header, 0);

        /* append payload (current ubuf) to header to form segmented ubuf */
        struct ubuf *payload = uref_detach_ubuf(uref);
        if (unlikely(!ubase_check(ubuf_block_append(header, payload)))) {
            upipe_warn(upipe, "could not append payload to header");
            ubuf_free(header);
            ubuf_free(payload);
            uref_free(uref);
            uref_free(next);
            return;
        }
        uref_attach_ubuf(uref, header);
        uref_clock_set_cr_dts_delay(uref, 0);
        upipe_rtp_h264_output(upipe, uref, upump_p);
        size -= split_size;
        fragment++;
        uref = next;
    }
}
Beispiel #12
0
/** @internal @This handles data from sound allocator.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_tblk_handle_sound(struct upipe *upipe, struct uref *uref,
                                    struct upump **upump_p)
{
    struct upipe_tblk *upipe_tblk = upipe_tblk_from_upipe(upipe);

    /* Always operate on the first channel plane. */
    const char *channel = NULL;
    if (unlikely(uref->ubuf == NULL ||
                 !ubase_check(ubuf_sound_plane_iterate(uref->ubuf, &channel)) ||
                 channel == NULL)) {
        uref_free(uref);
        upipe_throw_error(upipe, UBASE_ERR_INVALID);
        return;
    }

    /* First try the ubuf_mem_shared method. */
    struct ubuf *ubuf = ubuf_block_mem_alloc_from_sound(upipe_tblk->ubuf_mgr,
                                                        uref->ubuf, channel);
    if (unlikely(ubuf == NULL)) {
        /* We have to memcpy the thing. */
        size_t samples;
        uint8_t sample_size;
        if (unlikely(!ubase_check(uref_sound_size(uref, &samples,
                                                  &sample_size)))) {
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_INVALID);
            return;
        }

        size_t size = samples * sample_size;
        ubuf = ubuf_block_alloc(upipe_tblk->ubuf_mgr, size);
        if (unlikely(ubuf == NULL)) {
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        const uint8_t *r;
        if (unlikely(!ubase_check(uref_sound_plane_read_uint8_t(uref, channel,
                                                                0, -1, &r)))) {
            ubuf_free(ubuf);
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        uint8_t *w;
        int end = -1;
        if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &end, &w)))) {
            uref_sound_plane_unmap(uref, channel, 0, -1);
            ubuf_free(ubuf);
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        memcpy(w, r, size);
        ubuf_block_unmap(ubuf, 0);
        uref_sound_plane_unmap(uref, channel, 0, -1);
    }

    uref_attach_ubuf(uref, ubuf);
    upipe_tblk_output(upipe, uref, upump_p);
}
Beispiel #13
0
/** @internal @This prepends a PES header to a logical unit.
 *
 * @param upipe description structure of the pipe
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_ts_pese_work(struct upipe *upipe, struct upump **upump_p)
{
    struct upipe_ts_pese *upipe_ts_pese = upipe_ts_pese_from_upipe(upipe);
    if (ulist_empty(&upipe_ts_pese->next_pes))
        return;

    uint64_t pts = UINT64_MAX, dts = UINT64_MAX;
    struct uref *uref = uref_from_uchain(ulist_pop(&upipe_ts_pese->next_pes));

    size_t header_size;
    if (upipe_ts_pese->pes_id != PES_STREAM_ID_PRIVATE_2) {
        uref_clock_get_pts_prog(uref, &pts);
        uref_clock_get_dts_prog(uref, &dts);
        if (pts != UINT64_MAX) {
            if (dts != UINT64_MAX &&
                ((pts / CLOCK_SCALE) % POW2_33) !=
                    ((dts / CLOCK_SCALE) % POW2_33))
                header_size = PES_HEADER_SIZE_PTSDTS;
            else
                header_size = PES_HEADER_SIZE_PTS;
        } else
            header_size = PES_HEADER_SIZE_NOPTS;
    } else
        header_size = PES_HEADER_SIZE;
    if (header_size < upipe_ts_pese->pes_header_size)
        header_size = upipe_ts_pese->pes_header_size;

    struct ubuf *ubuf = ubuf_block_alloc(upipe_ts_pese->ubuf_mgr, header_size);
    if (unlikely(ubuf == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        goto upipe_ts_pese_work_err;
    }

    uint8_t *buffer;
    int size = -1;
    if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &size, &buffer)))) {
        ubuf_free(ubuf);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        goto upipe_ts_pese_work_err;
    }

    pes_init(buffer);
    pes_set_streamid(buffer, upipe_ts_pese->pes_id);
    size_t pes_length = upipe_ts_pese->next_pes_size + header_size -
                        PES_HEADER_SIZE;
    if (pes_length > UINT16_MAX) {
        if (unlikely((upipe_ts_pese->pes_id & PES_STREAM_ID_VIDEO_MPEG) != 
                     PES_STREAM_ID_VIDEO_MPEG))
            upipe_warn(upipe, "PES length > 65535 for a non-video stream");
        pes_set_length(buffer, 0);
    } else
        pes_set_length(buffer, pes_length);

    if (upipe_ts_pese->pes_id != PES_STREAM_ID_PRIVATE_2) {
        pes_set_headerlength(buffer, header_size - PES_HEADER_SIZE_NOPTS);
        pes_set_dataalignment(buffer);
        if (pts != UINT64_MAX) {
            pes_set_pts(buffer, (pts / CLOCK_SCALE) % POW2_33);
            if (dts != UINT64_MAX &&
                ((pts / CLOCK_SCALE) % POW2_33) !=
                    ((dts / CLOCK_SCALE) % POW2_33))
                pes_set_dts(buffer, (dts / CLOCK_SCALE) % POW2_33);
        }
    }
    ubuf_block_unmap(ubuf, 0);

    struct ubuf *payload = uref_detach_ubuf(uref);
    uref_attach_ubuf(uref, ubuf);
    if (unlikely(!ubase_check(uref_block_append(uref, payload)))) {
        uref_free(uref);
        ubuf_free(payload);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    /* intended pass-through */
upipe_ts_pese_work_err:
    uref_block_set_start(uref);
    upipe_ts_pese_output(upipe, uref, upump_p);

    struct uchain *uchain;
    while ((uchain = ulist_pop(&upipe_ts_pese->next_pes)) != NULL)
        upipe_ts_pese_output(upipe, uref_from_uchain(uchain), upump_p);
    upipe_ts_pese->next_pes_size = 0;
    upipe_ts_pese->next_pes_duration = 0;
}
Beispiel #14
0
/** @internal @This converts block urefs to sound urefs.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_block_to_sound_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p)
{

    struct upipe_block_to_sound *upipe_block_to_sound = upipe_block_to_sound_from_upipe(upipe);

    /* get block size */
    size_t block_size = 0;
    uref_block_size(uref, &block_size);

    /* drop incomplete samples */
    if ((block_size % upipe_block_to_sound->sample_size) != 0) {
        upipe_warn(upipe, "Incomplete samples detected");
    }

    int samples = block_size / upipe_block_to_sound->sample_size;
    block_size = samples * upipe_block_to_sound->sample_size;

    /* alloc sound ubuf */
    struct ubuf *ubuf_block_to_sound = ubuf_sound_alloc(upipe_block_to_sound->ubuf_mgr,
                                                        samples);

    if (unlikely(ubuf_block_to_sound == NULL)) {
        uref_free(uref);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }


    /* map sound ubuf for writing */
    int32_t *w;

    if (unlikely(!ubase_check(ubuf_sound_write_int32_t(ubuf_block_to_sound, 0, -1, &w,
                                                            upipe_block_to_sound->planes)))) {
        upipe_err(upipe, "could not write uref, dropping samples");
        ubuf_sound_unmap(ubuf_block_to_sound, 0, -1, upipe_block_to_sound->planes);
        ubuf_free(ubuf_block_to_sound);
        uref_free(uref);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }
    /* map block ubuf for reading */
    const uint8_t *r;
    int end = -1;
    if (unlikely(!ubase_check(uref_block_read(uref, 0, &end, &r)))) {
        upipe_err(upipe, "could not read uref, dropping samples");
        ubuf_sound_unmap(ubuf_block_to_sound, 0, -1, upipe_block_to_sound->planes);
        ubuf_block_unmap(uref->ubuf, 0);
        ubuf_free(ubuf_block_to_sound);
        uref_free(uref);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }
    /* copy block to sound */
    memcpy(w, r, block_size);
    /* unmap ubufs */
    ubuf_sound_unmap(ubuf_block_to_sound, 0, -1, upipe_block_to_sound->planes);
    ubuf_block_unmap(uref->ubuf, 0);
    /* attach sound ubuf to uref */
    uref_attach_ubuf(uref, ubuf_block_to_sound);
    /* output pipe */

    upipe_block_to_sound_output(upipe, uref, upump_p);
}
Beispiel #15
0
/** @internal @This merges a PSI section.
 *
 * @param upipe description structure of the pipe
 * @param uref uref pointing to (part of) a PSI section
 * @param upump_p reference to pump that generated the buffer
 * @return false if the uref has been entirely consumed
 */
static bool upipe_ts_psim_merge(struct upipe *upipe, struct uref *uref,
                                struct upump **upump_p)
{
    struct upipe_ts_psim *upipe_ts_psim = upipe_ts_psim_from_upipe(upipe);
    if (upipe_ts_psim->next_uref != NULL) {
        struct ubuf *ubuf = ubuf_dup(uref->ubuf);
        if (unlikely(ubuf == NULL ||
                     !ubase_check(uref_block_append(upipe_ts_psim->next_uref, ubuf)))) {
            upipe_ts_psim_flush(upipe);
            if (ubuf != NULL)
                ubuf_free(ubuf);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return false;
        }
    } else {
        /* Check for stuffing */
        uint8_t table_id;
        if (unlikely(!ubase_check(uref_block_extract(uref, 0, 1, &table_id)) ||
                     table_id == 0xff)) {
            return false;
        }

        upipe_ts_psim->next_uref = uref_dup(uref);
        if (unlikely(upipe_ts_psim->next_uref == NULL)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return false;
        }
    }

    size_t size = 0;
    UBASE_FATAL(upipe, uref_block_size(upipe_ts_psim->next_uref, &size))
    if (size < PSI_HEADER_SIZE)
        return false;

    uint8_t buffer[PSI_HEADER_SIZE];
    const uint8_t *psi_header = uref_block_peek(upipe_ts_psim->next_uref,
                                                0, PSI_HEADER_SIZE, buffer);
    assert(psi_header != NULL);

    uint16_t length = psi_get_length(psi_header);
    UBASE_FATAL(upipe, uref_block_peek_unmap(upipe_ts_psim->next_uref, 0,
                buffer, psi_header));

    if (unlikely(!psi_validate(psi_header) ||
                 length + PSI_HEADER_SIZE > PSI_PRIVATE_MAX_SIZE)) {
        upipe_warn(upipe, "wrong PSI header");
        upipe_ts_psim_flush(upipe);
        return false;
    }

    if (length + PSI_HEADER_SIZE > size)
        return false;

    UBASE_FATAL(upipe, uref_block_resize(upipe_ts_psim->next_uref, 0,
                length + PSI_HEADER_SIZE));
    upipe_ts_psim_output(upipe, upipe_ts_psim->next_uref, upump_p);
    upipe_ts_psim->next_uref = NULL;
    if (length + PSI_HEADER_SIZE == size)
        return false;

    size_t uref_size = 0;
    UBASE_FATAL(upipe, uref_block_size(uref, &uref_size))
    UBASE_FATAL(upipe, uref_block_resize(uref, length + PSI_HEADER_SIZE - (size - uref_size), -1));
    return true;
}
Beispiel #16
0
int main(int argc, char **argv)
{
    struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc();
    assert(umem_mgr != NULL);

    struct ubuf_mgr *mgr;
    struct ubuf *ubuf1, *ubuf2;
    const char *channel;
    size_t size;
    uint8_t sample_size;
    uint8_t *w;
    const uint8_t *r;

    /* packed s16 stereo */
    mgr = ubuf_sound_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr,
                                   4, 32);
    assert(mgr != NULL);
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "lr"));

    ubuf1 = ubuf_sound_alloc(mgr, 32);
    assert(ubuf1 != NULL);

    ubase_assert(ubuf_sound_size(ubuf1, &size, &sample_size));
    assert(size == 32);
    assert(sample_size == 4);

    channel = NULL;
    unsigned int nb_planes = 0;
    while (ubase_check(ubuf_sound_plane_iterate(ubuf1, &channel)) &&
           channel != NULL) {
        nb_planes++;
        assert(!strcmp(channel, "lr"));
    }
    assert(nb_planes == 1);

    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "lr", 0, -1, &r));
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "lr", 0, -1));

    fill_in(ubuf1);

    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "lr", 2, 1, &r));
    assert(*r == 'l' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "lr", 2, 1));

    ubuf2 = ubuf_dup(ubuf1);
    assert(ubuf2 != NULL);
    ubase_nassert(ubuf_sound_plane_write_uint8_t(ubuf1, "lr", 0, -1, &w));
    ubuf_free(ubuf2);

    ubase_nassert(ubuf_sound_resize(ubuf1, 0, 33));

    ubase_assert(ubuf_sound_resize(ubuf1, 2, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "lr", 0, -1, &r));
    assert(r[0] == 'l' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "lr", 0, -1));

    ubase_assert(ubuf_sound_resize(ubuf1, 0, 29));

    ubuf_free(ubuf1);

    ubuf_mgr_release(mgr);

    /* planar float 5.1 */
    mgr = ubuf_sound_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr,
                                   sizeof(float), 32);
    assert(mgr != NULL);
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "l"));
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "r"));
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "c"));
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "L"));
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "R"));
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "S"));

    ubuf1 = ubuf_sound_alloc(mgr, 32);
    assert(ubuf1 != NULL);

    ubase_assert(ubuf_sound_size(ubuf1, &size, &sample_size));
    assert(size == 32);
    assert(sample_size == sizeof(float));

    channel = NULL;
    nb_planes = 0;
    while (ubase_check(ubuf_sound_plane_iterate(ubuf1, &channel)) &&
           channel != NULL)
        nb_planes++;
    assert(nb_planes == 6);

    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "l", 0, -1, &r));
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "l", 0, -1));

    fill_in(ubuf1);

    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "l", 2, 1, &r));
    assert(*r == 'l' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "l", 2, 1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "r", 2, 1, &r));
    assert(*r == 'r' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "r", 2, 1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "c", 2, 1, &r));
    assert(*r == 'c' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "c", 2, 1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "L", 2, 1, &r));
    assert(*r == 'L' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "L", 2, 1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "R", 2, 1, &r));
    assert(*r == 'R' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "R", 2, 1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "S", 2, 1, &r));
    assert(*r == 'S' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "S", 2, 1));

    ubuf2 = ubuf_dup(ubuf1);
    assert(ubuf2 != NULL);
    ubase_nassert(ubuf_sound_plane_write_uint8_t(ubuf1, "l", 0, -1, &w));
    ubuf_free(ubuf2);

    ubase_nassert(ubuf_sound_resize(ubuf1, 0, 33));

    ubase_assert(ubuf_sound_resize(ubuf1, 2, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "l", 0, -1, &r));
    assert(r[0] == 'l' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "l", 0, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "r", 0, -1, &r));
    assert(r[0] == 'r' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "r", 0, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "c", 0, -1, &r));
    assert(r[0] == 'c' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "c", 0, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "L", 0, -1, &r));
    assert(r[0] == 'L' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "L", 0, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "R", 0, -1, &r));
    assert(r[0] == 'R' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "R", 0, -1));
    ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "S", 0, -1, &r));
    assert(r[0] == 'S' + 8);
    ubase_assert(ubuf_sound_plane_unmap(ubuf1, "S", 0, -1));

    ubase_assert(ubuf_sound_resize(ubuf1, 0, 29));

    ubuf_free(ubuf1);
    ubuf_mgr_release(mgr);

    /* sound -> block transformation */
    mgr = ubuf_sound_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr,
                                   4, 32);
    assert(mgr != NULL);
    ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "lr"));

    ubuf1 = ubuf_sound_alloc(mgr, 32);
    assert(ubuf1 != NULL);
    fill_in(ubuf1);

    struct ubuf_mgr *block_mgr = ubuf_block_mem_mgr_alloc(UBUF_POOL_DEPTH,
            UBUF_POOL_DEPTH, umem_mgr, 0, 0, 0, 0);
    struct ubuf *ubuf_block = ubuf_block_mem_alloc_from_sound(block_mgr,
                                                              ubuf1, "lr");
    assert(ubuf_block != NULL);
    ubase_assert(ubuf_block_size(ubuf_block, &size));
    assert(size == 32 * 4);
    int size2 = -1;
    ubase_assert(ubuf_block_read(ubuf_block, 0, &size2, &r));
    assert(size2 == 32 * 4);
    assert(r[0] == 'l');

    ubuf_free(ubuf_block);
    ubuf_mgr_release(block_mgr);
    ubuf_free(ubuf1);

    ubuf_mgr_release(mgr);
    umem_mgr_release(umem_mgr);
    return 0;
}
Beispiel #17
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 * @return false if the input must be blocked
 */
static bool upipe_speexdsp_handle(struct upipe *upipe, struct uref *uref,
                             struct upump **upump_p)
{
    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);

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

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

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

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

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

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

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

    int err;

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

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

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

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

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

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

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

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

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

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

    if (flow_def == NULL)
        return UBASE_ERR_INVALID;

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

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

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

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

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

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

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

    upipe_speexdsp_require_ubuf_mgr(upipe, flow_def);

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

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

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

    return UBASE_ERR_NONE;
}

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

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

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

    return urequest_provide_flow_format(request, flow);
}

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

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

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

        default:
            return UBASE_ERR_UNHANDLED;
    }
}

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

    struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe);

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

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

    upipe_throw_ready(upipe);
    return upipe;
}

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

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

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

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

    .upipe_mgr_control = NULL
};

/** @This returns the management structure for speexdsp pipes
 *
 * @return pointer to manager
 */
struct upipe_mgr *upipe_speexdsp_mgr_alloc(void)
{
    return &upipe_speexdsp_mgr;
}
Beispiel #18
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++;
}
Beispiel #19
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 * @return always true
 */
static bool upipe_filter_blend_handle(struct upipe *upipe, struct uref *uref,
                                      struct upump **upump_p)
{
    struct upipe_filter_blend *upipe_filter_blend = upipe_filter_blend_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        upipe_filter_blend_store_flow_def(upipe, NULL);
        upipe_filter_blend_require_ubuf_mgr(upipe, uref);
        return true;
    }

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

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

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

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

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

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

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

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

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

error:
    uref_free(uref);
    if (ubuf_deint) {
        ubuf_free(ubuf_deint);
    }
    return true;
}
Beispiel #20
0
/** @internal @This handles data from pic allocator.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_tblk_handle_pic(struct upipe *upipe, struct uref *uref,
                                  struct upump **upump_p)
{
    struct upipe_tblk *upipe_tblk = upipe_tblk_from_upipe(upipe);

    /* Always operate on the first chroma plane. */
    const char *chroma = NULL;
    if (unlikely(uref->ubuf == NULL ||
                 !ubase_check(ubuf_pic_plane_iterate(uref->ubuf, &chroma)) ||
                 chroma == NULL)) {
        uref_free(uref);
        upipe_throw_error(upipe, UBASE_ERR_INVALID);
        return;
    }

    /* First try the ubuf_mem_shared method. */
    struct ubuf *ubuf = ubuf_block_mem_alloc_from_pic(upipe_tblk->ubuf_mgr,
                                                      uref->ubuf, chroma);
    if (unlikely(ubuf == NULL)) {
        /* We have to memcpy the thing. */
        size_t hsize, vsize, stride;
        uint8_t macropixel, hsub, vsub, macropixel_size;
        if (unlikely(!ubase_check(uref_pic_size(uref, NULL, &vsize,
                                                NULL)) ||
                     !ubase_check(uref_pic_plane_size(uref, chroma,
                             &stride, NULL, &vsub, NULL)))) {
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_INVALID);
            return;
        }

        size_t size = stride * vsize / vsub;
        ubuf = ubuf_block_alloc(upipe_tblk->ubuf_mgr, size);
        if (unlikely(ubuf == NULL)) {
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        const uint8_t *r;
        if (unlikely(!ubase_check(uref_pic_plane_read(uref, chroma,
                            0, 0, -1, -1, &r)))) {
            ubuf_free(ubuf);
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        uint8_t *w;
        int end = -1;
        if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &end, &w)))) {
            uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1);
            ubuf_free(ubuf);
            uref_free(uref);
            upipe_throw_error(upipe, UBASE_ERR_ALLOC);
            return;
        }

        memcpy(w, r, size);
        ubuf_block_unmap(ubuf, 0);
        uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1);
    }

    uref_attach_ubuf(uref, ubuf);
    upipe_tblk_output(upipe, uref, upump_p);
}
Beispiel #21
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static bool upipe_s337_encaps_handle(struct upipe *upipe, struct uref *uref,
                                    struct upump **upump_p)
{
    struct upipe_s337_encaps *upipe_s337_encaps = upipe_s337_encaps_from_upipe(upipe);

    if (!upipe_s337_encaps->ubuf_mgr)
        return false;

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

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

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

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

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

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

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

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

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

        uref_block_unmap(uref, offset);

        block_size -= size;
        offset += size;
    }

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

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

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