예제 #1
0
static void upipe_rtp_opus_input(struct upipe *upipe, struct uref *uref,
                                  struct upump **upump_p)
{
    struct upipe_rtp_opus *upipe_rtp_opus = upipe_rtp_opus_from_upipe(upipe);

    uint64_t timestamp = 0;
    size_t block_size = 0;
    if (!ubase_check(uref_block_size(uref, &block_size))) {
        upipe_warn(upipe, "fail to get uref block size");
        return;
    }

    uref_rtp_get_timestamp(uref, &timestamp);
    uref_clock_set_pts_orig(uref, timestamp * TS_MULTIPLIER);

    uint64_t delta =
        (UINT_MAX + timestamp -
         (upipe_rtp_opus->last_rtp_timestamp % UINT_MAX)) % UINT_MAX;
    upipe_rtp_opus->last_rtp_timestamp += delta;
    uref_clock_set_pts_prog(uref, upipe_rtp_opus->last_rtp_timestamp * TS_MULTIPLIER);

    upipe_throw_clock_ref(upipe, uref, upipe_rtp_opus->last_rtp_timestamp * TS_MULTIPLIER, 0);
    upipe_throw_clock_ts(upipe, uref);

    upipe_rtp_opus_output(upipe, uref, upump_p);
}
예제 #2
0
/** @internal @This checks if a sync word begins just after the end of the
 * next frame.
 *
 * @param upipe description structure of the pipe
 * @param ready_p filled with true if a sync word was found
 * @param false if no sync word was found and resync is needed
 */
static bool upipe_a52f_check_frame(struct upipe *upipe, bool *ready_p)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    size_t size;
    *ready_p = false;
    if (!ubase_check(uref_block_size(upipe_a52f->next_uref, &size)))
        return false;
    if (size < upipe_a52f->next_frame_size)
        return true;

    uint8_t words[2];
    if (!ubase_check(uref_block_extract(upipe_a52f->next_uref,
                            upipe_a52f->next_frame_size, 2, words))) {
        /* not enough data */
        if (upipe_a52f->acquired) {/* avoid delaying packets unnecessarily */
            *ready_p = true;
        }
        return true;
    }
    if (words[0] != 0xb || words[1] != 0x77) {
        return false;
    }
    *ready_p = true;
    return true;
}
예제 #3
0
/** @internal @This tries to find TS packets in the buffered input 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_ts_check_input(struct upipe *upipe, struct uref *uref,
                                 struct upump **upump_p)
{
    struct upipe_ts_check *upipe_ts_check = upipe_ts_check_from_upipe(upipe);
    size_t size;
    if (unlikely(!ubase_check(uref_block_size(uref, &size)))) {
        uref_free(uref);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    while (size > upipe_ts_check->output_size) {
        struct uref *next = uref_block_split(uref, upipe_ts_check->output_size);
        if (unlikely(next == NULL)) {
            uref_free(uref);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }
        if (!upipe_ts_check_check(upipe, uref, upump_p)) {
            uref_free(next);
            return;
        }

        size -= upipe_ts_check->output_size;
        uref = next;
    }
    if (size == upipe_ts_check->output_size)
        upipe_ts_check_check(upipe, uref, upump_p);
}
예제 #4
0
/** @internal @This handles audio input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_osx_audioqueue_sink_input_audio(struct upipe *upipe,
        struct uref *uref, struct upump **upump_p)
{
    struct upipe_osx_audioqueue_sink *osx_audioqueue =
        upipe_osx_audioqueue_sink_from_upipe(upipe);
    struct AudioQueueBuffer *qbuf;
    size_t size = 0;

    if (unlikely(!ubase_check(uref_block_size(uref, &size)))) {
        upipe_warn(upipe, "could not get block size");
        uref_free(uref);
        return;
    }

    /* TODO block ? */
#if 0
    upump_mgr_use(upump->mgr);
    upump_mgr_sink_block(upump->mgr);
#endif

    /* allocate queue buf, extract block, enqueue
     * Audioqueue has no support for "external" buffers */
    AudioQueueAllocateBuffer(osx_audioqueue->queue, size, &qbuf);
    uref_block_extract(uref, 0, -1, qbuf->mAudioData);
    qbuf->mAudioDataByteSize = size;
    qbuf->mUserData = (*upump_p)->mgr;
    AudioQueueEnqueueBuffer(osx_audioqueue->queue, qbuf, 0, NULL);

    uref_free(uref);
}
예제 #5
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);
}
예제 #6
0
static bool upipe_dveo_asi_sink_write(struct upipe *upipe, struct uref *uref,
        bool *reset_first_timestamp)
{
    struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe);
    for (;;) {
        int iovec_count = uref_block_iovec_count(uref, 0, -1);
        if (unlikely(iovec_count == -1)) {
            upipe_warn(upipe, "cannot read ubuf buffer");
            break;
        }
        if (unlikely(iovec_count == 0)) {
            break;
        }

        struct iovec iovecs[iovec_count];
        if (unlikely(!ubase_check(uref_block_iovec_read(uref, 0, -1,
                                                        iovecs)))) {
            upipe_warn(upipe, "cannot read ubuf buffer");
            break;
        }

        ssize_t ret = writev(upipe_dveo_asi_sink->fd, iovecs, iovec_count);
        uref_block_iovec_unmap(uref, 0, -1, iovecs);

        if (unlikely(ret == -1)) {
            switch (errno) {
                case EINTR:
                    continue;
                case EAGAIN:
#if EAGAIN != EWOULDBLOCK
                case EWOULDBLOCK:
#endif
                    //upipe_notice_va(upipe, "polling");
                    upipe_dveo_asi_sink_poll(upipe);
                    return false;
                default:
                    break;
            }
            upipe_warn_va(upipe, "write error to device %d (%m)", upipe_dveo_asi_sink->card_idx);
            upipe_dveo_asi_sink_set_upump(upipe, NULL);
            upipe_throw_sink_end(upipe);
            break;
        }

        size_t uref_size;
        if (ubase_check(uref_block_size(uref, &uref_size)) &&
            uref_size == ret) {
            /* wrote succeeded */
            *reset_first_timestamp = false;
            break;
        }
        uref_block_resize(uref, ret, -1);
    }

    return true;
}
예제 #7
0
/** @internal @This checks if a burst is complete.
 *
 * @param upipe description structure of the pipe
 * @param true if the burst is complete
 */
static bool upipe_s337d_check_frame(struct upipe *upipe)
{
    struct upipe_s337d *upipe_s337d = upipe_s337d_from_upipe(upipe);
    size_t size;
    if (!ubase_check(uref_block_size(upipe_s337d->next_uref, &size))) {
        upipe_s337d->next_frame_discard = true;
        return true;
    }
    return size >= upipe_s337d->next_frame_size + S337_PREAMBLE_SIZE;
}
예제 #8
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);
}
예제 #9
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_htons_input(struct upipe *upipe, struct uref *uref,
                              struct upump **upump_p)
{
    struct ubuf *ubuf;
    size_t size = 0;
    int remain, bufsize = -1, offset = 0;
    uint8_t *buf = NULL;

    /* block size */
    if (unlikely(!ubase_check(uref_block_size(uref, &size)))) {
        upipe_warn(upipe, "could not read uref block size");
        uref_free(uref);
        return;
    }
    /* copy ubuf if shared or not 16b-unaligned or segmented */
    bufsize = -1;
    if (!ubase_check(uref_block_write(uref, 0, &bufsize, &buf)) ||
        ((uintptr_t)buf & 1) || bufsize != size) {
        ubuf = ubuf_block_copy(uref->ubuf->mgr, uref->ubuf, 0, size);
        if (unlikely(!ubuf)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(uref);
            return;
        }
        uref_attach_ubuf(uref, ubuf);
    } else {
        uref_block_unmap(uref, 0);
    }

    /* process ubuf chunks */
    while (size > 0) {
        bufsize = -1;
        if (unlikely(!ubase_check(uref_block_write(uref, offset, &bufsize,
                                  &buf)))) {
            upipe_warn(upipe, "unexpected buffer error");
            uref_free(uref);
            return;
        }
        if (unlikely((uintptr_t)buf & 1)) {
            upipe_warn_va(upipe, "unaligned buffer: %p", buf);
        }
        for (remain = bufsize; remain > 1; remain -= 2) {
            *(uint16_t *)buf = htons(*(uint16_t *)buf);
            buf += 2;
        }

        uref_block_unmap(uref, offset);
        offset += bufsize;
        size -= bufsize;
    }

    upipe_htons_output(upipe, uref, upump_p);
}
예제 #10
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;
    }
}
예제 #11
0
파일: upipe_dump.c 프로젝트: cmassiot/upipe
static void upipe_dump_input(struct upipe *upipe, struct uref *uref,
                             struct upump **upump_p)
{
    struct upipe_dump *upipe_dump = upipe_dump_from_upipe(upipe);

    uref_dump(uref, upipe->uprobe);

    size_t total_size;
    ubase_assert(uref_block_size(uref, &total_size));

    upipe_notice_va(upipe, "dumping ubuf %p of size %zu",
                    uref->ubuf, total_size);

    if (upipe_dump->max_len != (size_t)-1 &&
        total_size > upipe_dump->max_len)
        total_size = upipe_dump->max_len;

    unsigned int count = 0;
    uint8_t line[16];

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

        ubase_assert(uref_block_read(uref, offset, &size, &buf));
        assert(size != 0);

        total_size -= size;

        for (unsigned i = 0; i < size; i++, count++) {
            line[count % 16] = buf[i];

            if (!((count + 1) % 16) || (!total_size && (i + 1 == size)))
                upipe_dump_line(upipe, count - (count % 16),
                                line, (count % 16) + 1);
        }

        ubase_assert(uref_block_unmap(uref, offset));
        offset += size;
    }
#define UPIPE_DUMP_SEP \
    "--------------------------------------------" \
    "-------------------------------------------"
    upipe_notice(upipe, UPIPE_DUMP_SEP);
    upipe_dump_output(upipe, uref, upump_p);
}
예제 #12
0
/** @internal @This merges the new access unit into a possibly existing
 * incomplete PES, and outputs the PES if possible.
 *
 * @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_ts_pese_handle(struct upipe *upipe, struct uref *uref,
                                 struct upump **upump_p)
{
    struct upipe_ts_pese *upipe_ts_pese = upipe_ts_pese_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        upipe_ts_pese_work(upipe, NULL);

        uref_ts_flow_get_pes_id(uref, &upipe_ts_pese->pes_id);
        upipe_ts_pese->pes_header_size = 0;
        uref_ts_flow_get_pes_header(uref, &upipe_ts_pese->pes_header_size);
        upipe_ts_pese->pes_min_duration = 0;
        uref_ts_flow_get_pes_min_duration(uref,
                                          &upipe_ts_pese->pes_min_duration);
        upipe_ts_pese->input_latency = 0;
        uref_clock_get_latency(uref, &upipe_ts_pese->input_latency);
        if (unlikely(!ubase_check(uref_clock_set_latency(uref,
                                        upipe_ts_pese->input_latency +
                                        upipe_ts_pese->pes_min_duration))))
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        upipe_ts_pese_store_flow_def(upipe, NULL);
        upipe_ts_pese_require_ubuf_mgr(upipe, uref);
        return true;
    }

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

    uint64_t uref_duration = upipe_ts_pese->pes_min_duration;
    uref_clock_get_duration(uref, &uref_duration);
    size_t uref_size = 0;
    uref_block_size(uref, &uref_size);
    uref_block_delete_start(uref);

    ulist_add(&upipe_ts_pese->next_pes, uref_to_uchain(uref));
    upipe_ts_pese->next_pes_duration += uref_duration;
    upipe_ts_pese->next_pes_size += uref_size;

    if (upipe_ts_pese->next_pes_duration >= upipe_ts_pese->pes_min_duration)
        upipe_ts_pese_work(upipe, upump_p);
    return true;
}
예제 #13
0
/** @internal @This tries to find TS packets in the buffered input 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_ts_check_input(struct upipe *upipe, struct uref *uref,
                                 struct upump **upump_p)
{
    struct upipe_ts_check *upipe_ts_check = upipe_ts_check_from_upipe(upipe);
    size_t size;
    if (unlikely(!ubase_check(uref_block_size(uref, &size)))) {
        uref_free(uref);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    bool first = true;
    while (size > upipe_ts_check->output_size) {
        struct uref *output = uref_block_splice(uref, 0,
                                                upipe_ts_check->output_size);
        if (unlikely(output == NULL)) {
            uref_free(uref);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }

        if (!first)
            uref_flow_delete_discontinuity(output);
        first = false;

        if (!upipe_ts_check_check(upipe, output, upump_p)) {
            uref_free(uref);
            return;
        }

        uref_block_resize(uref, upipe_ts_check->output_size, -1);
        size -= upipe_ts_check->output_size;
    }

    if (!first)
        uref_flow_delete_discontinuity(uref);

    if (size == upipe_ts_check->output_size)
        upipe_ts_check_check(upipe, uref, upump_p);
}
예제 #14
0
/** @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);
}
예제 #15
0
static void upipe_rtp_h264_input(struct upipe *upipe,
                                struct uref *uref,
                                struct upump **upump_p)
{
    size_t bz = 0;
    if (!ubase_check(uref_block_size(uref, &bz))) {
        upipe_err(upipe, "fail to get uref block size");
        return upipe_rtp_h264_drop(upipe, uref);
    }

    uint8_t buf[bz];
    int size = bz;
    if (unlikely(!ubase_check(uref_block_extract(uref, 0, size, buf)))) {
        upipe_err(upipe, "fail to read from uref");
        return upipe_rtp_h264_drop(upipe, uref);
    }

    uint8_t s_len;
    const uint8_t *s = upipe_mpeg_scan(buf, buf + size, &s_len);
    if (s != buf) {
        upipe_err(upipe, "uref does not start with a mpeg start code");
        return upipe_rtp_h264_drop(upipe, uref);
    }

    while (s < buf + size) {
        uint8_t e_len = 0;
        const uint8_t *e = upipe_mpeg_scan(s + s_len, buf + size, &e_len);
        if (!e)
            e = buf + size;

        struct uref *part = uref_block_splice(uref, s - buf + s_len + 1,
                                              e - (s + s_len + 1));
        upipe_rtp_h264_output_nalu(upipe, *(s + s_len), part, upump_p);
        s = e;
        s_len = e_len;
    }

    uref_free(uref);
}
예제 #16
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++;
}
예제 #17
0
/** @internal @This outputs audio buffers
 *
 * @param upipe description structure of the pipe
 * @param frame AVFrame structure
 * @param upump upump structure
 */
static void upipe_avcdec_output_audio(struct upipe *upipe, AVFrame *frame,
                                     struct upump *upump)
{
    struct ubuf *ubuf;
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    struct uref *uref = frame->opaque;
    int bufsize = -1, avbufsize;
    size_t size = 0;
    uint8_t *buf;
    AVCodecContext *context = upipe_avcdec->context;

    /* fetch audio sample size (in case it has been reduced) */
    avbufsize = av_samples_get_buffer_size(NULL, context->channels,
                       frame->nb_samples, context->sample_fmt, 1);

    /* if uref has no attached ubuf (ie DR not supported) */
    if (unlikely(!uref->ubuf)) {
        ubuf = ubuf_block_alloc(upipe_avcdec->ubuf_mgr, avbufsize);
        if (unlikely(!ubuf)) {
            upipe_throw_aerror(upipe);
            return;
        }

        ubuf_block_write(ubuf, 0, &bufsize, &buf);
        memcpy(buf, frame->data[0], bufsize);

        uref_attach_ubuf(uref, ubuf);
    }

    /* unmap, reduce block if needed */
    uref_block_unmap(uref, 0);
    uref_block_size(uref, &size);
    if (unlikely(size != avbufsize)) {
        uref_block_resize(uref, 0, avbufsize);
    }

    /* TODO: set attributes/need a real ubuf_audio structure (?) */
    if (!upipe_avcdec->output_flow) {
        #if 0
        struct uref *outflow = uref_sound_flow_alloc_def(upipe_avcdec->uref_mgr,
                    context->channels,
                    av_get_bytes_per_sample(context->sample_fmt));
        #else

        struct uref *outflow = uref_block_flow_alloc_def(upipe_avcdec->uref_mgr,
                                                        "sound.");

        #endif
        uref_sound_flow_set_channels(outflow, context->channels);
        uref_sound_flow_set_sample_size(outflow,
                                 av_get_bytes_per_sample(context->sample_fmt));
        uref_sound_flow_set_rate(outflow, context->sample_rate);

        upipe_avcdec_store_flow_def(upipe, outflow);
    }

    /* samples in uref */
    uref_sound_flow_set_samples(uref, frame->nb_samples);

    /* index rap attribute */
    upipe_avcdec_set_index_rap(upipe, uref);

    upipe_avcdec_output(upipe, uref, upump);
}
예제 #18
0
/** @internal @This outputs data to the file sink.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to pump that generated the buffer
 * @return true if the uref was processed
 */
static bool upipe_fsink_output(struct upipe *upipe, struct uref *uref,
                               struct upump **upump_p)
{
    struct upipe_fsink *upipe_fsink = upipe_fsink_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        uint64_t latency = 0;
        uref_clock_get_latency(uref, &latency);
        if (latency > upipe_fsink->latency)
            upipe_fsink->latency = latency;
        uref_free(uref);
        return true;
    }

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

    if (likely(upipe_fsink->uclock == NULL))
        goto write_buffer;

    uint64_t cr_sys = 0;
    if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) {
        upipe_warn(upipe, "received non-dated buffer");
        goto write_buffer;
    }

    uint64_t now = uclock_now(upipe_fsink->uclock);
    cr_sys += upipe_fsink->latency;
    if (unlikely(now < cr_sys)) {
        upipe_fsink_wait_upump(upipe, cr_sys - now, upipe_fsink_watcher);
        return false;
    }

write_buffer:
    for ( ; ; ) {
        int iovec_count = uref_block_iovec_count(uref, 0, -1);
        if (unlikely(iovec_count == -1)) {
            uref_free(uref);
            upipe_warn(upipe, "cannot read ubuf buffer");
            break;
        }
        if (unlikely(iovec_count == 0)) {
            uref_free(uref);
            break;
        }

        struct iovec iovecs[iovec_count];
        if (unlikely(!ubase_check(uref_block_iovec_read(uref, 0, -1,
                                                        iovecs)))) {
            uref_free(uref);
            upipe_warn(upipe, "cannot read ubuf buffer");
            break;
        }

        ssize_t ret = writev(upipe_fsink->fd, iovecs, iovec_count);
        uref_block_iovec_unmap(uref, 0, -1, iovecs);

        if (unlikely(ret == -1)) {
            switch (errno) {
                case EINTR:
                    continue;
                case EAGAIN:
#if EAGAIN != EWOULDBLOCK
                case EWOULDBLOCK:
#endif
                    upipe_fsink_poll(upipe);
                    return false;
                case EBADF:
                case EFBIG:
                case EINVAL:
                case EIO:
                case ENOSPC:
                case EPIPE:
                default:
                    break;
            }
            uref_free(uref);
            upipe_warn_va(upipe, "write error to %s (%m)", upipe_fsink->path);
            upipe_fsink_set_upump(upipe, NULL);
            upipe_throw_sink_end(upipe);
            return true;
        }

        size_t uref_size;
        if (ubase_check(uref_block_size(uref, &uref_size)) &&
            uref_size == ret) {
            uref_free(uref);
            break;
        }
        uref_block_resize(uref, ret, -1);
    }
    return true;
}
예제 #19
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;
}
예제 #20
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);
}
예제 #21
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;
    }
}
예제 #22
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;
}