Example #1
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;
}
Example #2
0
/** @internal @This handles input buffers.
 *
 * @param upipe description structure of the pipe
 * @param uref input buffer to handle
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_ablk_input(struct upipe *upipe,
                             struct uref *uref,
                             struct upump **upump_p)
{
    struct upipe_ablk *upipe_ablk = upipe_ablk_from_upipe(upipe);
    struct uref *input_flow_def = upipe_ablk->input_flow_def;
    struct uref *flow_def = upipe_ablk->flow_def;

    if (uref->ubuf) {
        upipe_ablk_output(upipe, uref, upump_p);
        return;
    }

    if (unlikely(!input_flow_def)) {
        upipe_warn(upipe, "no input flow definition");
        uref_free(uref);
        return;
    }

    if (unlikely(!flow_def)) {
        upipe_warn(upipe, "no output flow definition set");
        uref_free(uref);
        return;
    }

    if (unlikely(!upipe_ablk->ubuf_mgr)) {
        upipe_warn(upipe, "no ubuf manager set");
        uref_free(uref);
        return;
    }

    if (unlikely(!upipe_ablk->ubuf)) {
        upipe_verbose(upipe, "allocate blank sound");

        uint64_t samples = 0;
        uint8_t sample_size = 0;
        uref_sound_flow_get_samples(flow_def, &samples);
        uref_sound_flow_get_sample_size(flow_def, &sample_size);

        struct ubuf *ubuf = ubuf_sound_alloc(upipe_ablk->ubuf_mgr, samples);
        if (unlikely(!ubuf)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(uref);
            return;
        }

        const char *channel;
        uint8_t *buf = NULL;
        ubuf_sound_foreach_plane(ubuf, channel) {
            ubuf_sound_plane_write_uint8_t(ubuf, channel, 0, -1, &buf);
            memset(buf, 0, sample_size * samples);
            ubuf_sound_plane_unmap(ubuf, channel, 0, -1);
        }
Example #3
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);
}
/** @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);
}
Example #5
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);
}
Example #6
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;
}
Example #7
0
/** helper phony pipe */
static void test_input(struct upipe *upipe, struct uref *uref,
                       struct upump **upump_p)
{
    struct x264_test *x264_test = x264_test_from_upipe(upipe);
    uint64_t pts = 0, dts = 0;
    if (uref->udict != NULL) {
        udict_dump(uref->udict, upipe->uprobe);
    }
    if (!ubase_check(uref_clock_get_pts_prog(uref, &pts))) {
        upipe_warn(upipe, "received packet with no pts");
    }
    if (!ubase_check(uref_clock_get_dts_prog(uref, &dts))) {
        upipe_warn(upipe, "received packet with no dts");
    }
    upipe_dbg_va(upipe, "received pic %d, pts: %"PRIu64" , dts: %"PRIu64,
                 x264_test->counter, pts, dts);
    x264_test->counter++;

    uref_free(uref);
}
Example #8
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_filter_ebur128_input(struct upipe *upipe, struct uref *uref,
                                       struct upump **upump_p)
{
    struct upipe_filter_ebur128 *upipe_filter_ebur128 =
                                 upipe_filter_ebur128_from_upipe(upipe);
    double loud = 0, lra = 0, global = 0;
    size_t samples;
    if (unlikely(!ubase_check(uref_sound_size(uref, &samples, NULL)))) {
        upipe_warn(upipe, "invalid sound buffer");
        uref_free(uref);
        return;
    }
    const char *channel = NULL;
    const int16_t *buf = NULL;
    if (ubase_check(uref_sound_plane_iterate(uref, &channel)) && channel) {
        if (unlikely(!ubase_check(uref_sound_plane_read_int16_t(uref,
                channel, 0, -1, &buf)))) {
            upipe_warn(upipe, "error mapping sound buffer");
            uref_free(uref);
            return;
        }

        if (unlikely((uintptr_t)buf & 1)) {
            upipe_warn(upipe, "unaligned buffer");
        }
        ebur128_add_frames_short(upipe_filter_ebur128->st, buf, samples);
        uref_sound_plane_unmap(uref, channel, 0, -1);
    }
    ebur128_loudness_momentary(upipe_filter_ebur128->st, &loud);
    ebur128_loudness_range(upipe_filter_ebur128->st, &lra);
    ebur128_loudness_global(upipe_filter_ebur128->st, &global);

    uref_ebur128_set_momentary(uref, loud);
    uref_ebur128_set_lra(uref, lra);
    uref_ebur128_set_global(uref, global);

    upipe_verbose_va(upipe, "loud %f lra %f global %f", loud, lra, global);

    upipe_filter_ebur128_output(upipe, uref, upump_p);
}
Example #9
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);
}
Example #10
0
/** @internal @This handles input buffer of the blank source pipe. This buffer
 * is supposed to be a picture or a sound to set as source buffer of the blank
 * pipes (audio/video blank pipe generator).
 *
 * @param upipe description structure of the pipe
 * @param uref uref reference picture or sound
 * @param upump_p is ignored
 */
static void upipe_blksrc_input(struct upipe *upipe,
                               struct uref *uref,
                               struct upump **upump_p)
{
    struct upipe_blksrc *upipe_blksrc = upipe_blksrc_from_upipe(upipe);
    if (unlikely(!upipe_blksrc->flow_def)) {
        upipe_warn(upipe, "flow def is not set");
        uref_free(uref);
    }
    else if (ubase_check(uref_flow_match_def(upipe_blksrc->flow_def,
                                             UREF_PIC_FLOW_DEF))) {
        upipe_dbg(upipe, "set picture buffer");
        upipe_vblk_set_pic(upipe_blksrc->blk, uref);
    }
    else if (ubase_check(uref_flow_match_def(upipe_blksrc->flow_def,
                                             UREF_SOUND_FLOW_DEF)))
        upipe_ablk_set_sound(upipe_blksrc->blk, uref);
    else {
        upipe_warn(upipe, "unsupported flow definition");
        uref_free(uref);
    }
}
Example #11
0
/** @internal @This tries to output frames from the queue of input buffers.
 *
 * @param upipe description structure of the pipe
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_a52f_work(struct upipe *upipe, struct upump **upump_p)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    while (upipe_a52f->next_uref != NULL) {
        if (unlikely(!upipe_a52f->acquired)) {
            size_t dropped = 0;
            bool ret = upipe_a52f_scan(upipe, &dropped);
            upipe_a52f_consume_uref_stream(upipe, dropped);
            if (!ret)
                return;
        }
        if (upipe_a52f->next_frame_size == -1 &&
            !upipe_a52f_parse_header(upipe)) {
            upipe_warn(upipe, "invalid header");
            upipe_a52f_consume_uref_stream(upipe, 1);
            upipe_a52f_sync_lost(upipe);
            continue;
        }
        if (upipe_a52f->next_frame_size == -1)
            return; /* not enough data */


        bool ready;
        if (unlikely(!upipe_a52f_check_frame(upipe, &ready))) {
            upipe_warn(upipe, "invalid frame");
            upipe_a52f_consume_uref_stream(upipe, 1);
            upipe_a52f->next_frame_size = -1;
            upipe_a52f_sync_lost(upipe);
            continue;
        }
        if (!ready)
            return; /* not enough data */

        upipe_a52f_sync_acquired(upipe);
        upipe_a52f_output_frame(upipe, upump_p);
        upipe_a52f->next_frame_size = -1;
    }
}
Example #12
0
/** @internal @This inputs data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_nacl_audio_input(struct upipe *upipe, struct uref *uref, 
                                   struct upump **upump_p)
{    
    struct upipe_nacl_audio *upipe_nacl_audio =
        upipe_nacl_audio_from_upipe(upipe);
    size_t uref_size;
    if (unlikely(!ubase_check(uref_sound_size(uref, &uref_size, NULL)))) {
        upipe_warn(upipe, "unable to read uref");
        uref_free(uref);
        return;
    }

    if (unlikely(!upipe_nacl_audio->started && !upipe_nacl_audio_open(upipe))) {
        upipe_warn(upipe, "unable to open device");
        uref_free(uref);
        return;
    }

    uint64_t uref_pts;
    if (likely(ubase_check(uref_clock_get_pts_sys(uref, &uref_pts)))) {
        uref_pts += upipe_nacl_audio->latency;
        uref_clock_set_pts_sys(uref, uref_pts);
    }

    if (!upipe_nacl_audio_check_input(upipe)) {
        upipe_nacl_audio_hold_input(upipe, uref);
        upipe_nacl_audio_block_input(upipe, upump_p);
    } else if (!upipe_nacl_audio_handle(upipe, uref, upump_p)) {
        if (!upipe_nacl_audio_check_watcher(upipe)) {
            upipe_warn(upipe, "unable to spool uref");
            uref_free(uref);
            return;
        }
        upipe_nacl_audio_hold_input(upipe, uref);
        upipe_nacl_audio_block_input(upipe, upump_p);
        upump_start(upipe_nacl_audio->upump);
    }
}
/** @internal @This creates a new audioqueue
 * @param upipe description structure of the pipe
 * @param flow description structure of the flow
 * @return an error code
 */
static int upipe_osx_audioqueue_sink_set_flow_def(struct upipe *upipe,
        struct uref *flow)
{
    OSStatus status;
    uint64_t sample_rate = 0; /* hush gcc */
    uint8_t channels = 0;
    uint8_t sample_size = 0;
    struct AudioStreamBasicDescription fmt;
    struct upipe_osx_audioqueue_sink *osx_audioqueue =
        upipe_osx_audioqueue_sink_from_upipe(upipe);

    if (unlikely(osx_audioqueue->queue)) {
        upipe_osx_audioqueue_sink_remove(upipe);
    }

    /* retrieve flow format information */
    uref_sound_flow_get_rate(flow, &sample_rate);
    uref_sound_flow_get_sample_size(flow, &sample_size);
    uref_sound_flow_get_channels(flow, &channels);

    /* build format description */
    memset(&fmt, 0, sizeof(struct AudioStreamBasicDescription));
    fmt.mSampleRate = sample_rate;
    fmt.mFormatID = kAudioFormatLinearPCM;
    fmt.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    fmt.mFramesPerPacket = 1;
    fmt.mChannelsPerFrame = channels;
    fmt.mBytesPerPacket = fmt.mBytesPerFrame = sample_size * channels;
    fmt.mBitsPerChannel = sample_size * 8;

    /* create queue */
    status = AudioQueueNewOutput(&fmt, upipe_osx_audioqueue_sink_cb, upipe,
                                 NULL, kCFRunLoopCommonModes, 0, &osx_audioqueue->queue);
    if (unlikely(status == kAudioFormatUnsupportedDataFormatError)) {
        upipe_warn(upipe, "unsupported data format");
        return UBASE_ERR_EXTERNAL;
    }

    /* change volume */
    AudioQueueSetParameter(osx_audioqueue->queue, kAudioQueueParam_Volume,
                           osx_audioqueue->volume);

    /* start queue ! */
    AudioQueueStart(osx_audioqueue->queue, NULL);
    upipe_notice_va(upipe, "audioqueue started (%uHz, %hhuch, %db)",
                    sample_rate, channels, sample_size*8);

    return UBASE_ERR_NONE;
}
Example #14
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;
    }
}
Example #15
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump pump that generated the buffer
 */
static void _upipe_multicat_probe_input(struct upipe *upipe, struct uref *uref,
                                       struct upump *upump)
{
    struct upipe_multicat_probe *upipe_multicat_probe = upipe_multicat_probe_from_upipe(upipe);
    uint64_t systime = 0;
    int64_t newidx;

    if (unlikely(!uref_clock_get_systime(uref, &systime))) {
        upipe_warn(upipe, "uref has no systime");
    }
    newidx = (systime/upipe_multicat_probe->rotate);
    if (upipe_multicat_probe->idx != newidx) {
        upipe_throw(upipe, UPROBE_MULTICAT_PROBE_ROTATE,
                    UPIPE_MULTICAT_PROBE_SIGNATURE, uref, newidx);
        upipe_multicat_probe->idx = newidx;
    }

    upipe_multicat_probe_output(upipe, uref, upump);
}
Example #16
0
/** @internal @This handles input uref.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump upump structure
 */
static void upipe_avcdec_input(struct upipe *upipe, struct uref *uref,
                              struct upump *upump)
{
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    if (upipe_avcdec->uref_mgr == NULL) {
        upipe_throw_need_uref_mgr(upipe);
        if (unlikely(upipe_avcdec->uref_mgr == NULL)) {
            uref_free(uref);
            return;
        }
    }

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

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

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

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

    upipe_avcdec_input_packet(upipe, uref, upump);
}
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_osx_audioqueue_sink_input(struct upipe *upipe,
        struct uref *uref, struct upump **upump_p)
{
    struct upipe_osx_audioqueue_sink *osx_audioqueue =
        upipe_osx_audioqueue_sink_from_upipe(upipe);

    /* empty uref */
    if (unlikely(!uref->ubuf)) {
        uref_free(uref);
        return;
    }

    /* check queue */
    if (unlikely(!osx_audioqueue->queue)) {
        upipe_warn(upipe, "audioqueue not configured");
        uref_free(uref);
        return;
    }

    upipe_osx_audioqueue_sink_input_audio(upipe, uref, upump_p);
}
Example #18
0
/** @internal @This parses A/52 Annex E header.
 *
 * @param upipe description structure of the pipe
 * @return false in case the header is inconsistent
 */
static bool upipe_a52f_parse_a52e(struct upipe *upipe)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    uint8_t header[A52_SYNCINFO_SIZE];
    if (unlikely(!ubase_check(uref_block_extract(upipe_a52f->next_uref, 0,
                                                 sizeof(header), header))))
        return true; /* not enough data */

    if (likely(a52e_sync_compare_formats(header, upipe_a52f->sync_header))) {
        /* identical sync */
        upipe_a52f->next_frame_size =
            a52e_get_frame_size(a52e_get_frmsiz(header));
        return true;
    }

    /* sample rate */
    uint64_t samplerate;
    switch (a52e_get_fscod(header)) {
        case A52_FSCOD_48KHZ:
            samplerate = 48000;
            break;
        case A52_FSCOD_441KHZ:
            samplerate = 44100;
            break;
        case A52_FSCOD_32KHZ:
            samplerate = 32000;
            break;
        case A52_FSCOD_RESERVED:
            switch (a52e_get_fscod2(header)) {
                case A52E_FSCOD2_24KHZ:
                    samplerate = 24000;
                    break;
                case A52E_FSCOD2_2205KHZ:
                    samplerate = 22050;
                    break;
                case A52E_FSCOD2_16KHZ:
                    samplerate = 16000;
                    break;
                default:
                    upipe_warn(upipe, "reserved fscod2");
                    return false;
            }
            break;
        default: /* never reached */
            return false;
    }

    /* frame size */
    upipe_a52f->next_frame_size = a52e_get_frame_size(a52e_get_frmsiz(header));

    /* channels */
    int acmod = a52e_get_acmod(header);
    int channels = acmod_chans[acmod].nfchans + a52e_get_lfeon(header);

    uint64_t octetrate =
          (upipe_a52f->next_frame_size * samplerate + A52_FRAME_SAMPLES - 1) /
          A52_FRAME_SAMPLES;
    memcpy(upipe_a52f->sync_header, header, A52_SYNCINFO_SIZE);
    upipe_a52f->samplerate = samplerate;

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

    UBASE_FATAL(upipe, uref_flow_set_complete(flow_def))
    UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.eac3.sound."))
    UBASE_FATAL(upipe, uref_sound_flow_set_samples(flow_def, A52_FRAME_SAMPLES))
    UBASE_FATAL(upipe, uref_sound_flow_set_rate(flow_def, samplerate))
    UBASE_FATAL(upipe, uref_sound_flow_set_channels(flow_def, channels))
    UBASE_FATAL(upipe, uref_clock_set_latency(flow_def,
                upipe_a52f->input_latency +
                UCLOCK_FREQ * A52_FRAME_SAMPLES / samplerate))
    UBASE_FATAL(upipe, uref_block_flow_set_octetrate(flow_def, octetrate))

    flow_def = upipe_a52f_store_flow_def_attr(upipe, flow_def);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return false;
    }
    upipe_a52f_store_flow_def(upipe, flow_def);

    return true;
}
Example #19
0
/** @internal @This handles input.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump_p reference to upump structure
 */
static void upipe_filter_ebur128_input(struct upipe *upipe, struct uref *uref,
                                       struct upump **upump_p)
{
    struct upipe_filter_ebur128 *upipe_filter_ebur128 =
                                 upipe_filter_ebur128_from_upipe(upipe);
    double loud = 0, lra = 0, global = 0;

    if (unlikely(upipe_filter_ebur128->output_flow == NULL)) {
        upipe_err_va(upipe, "invalid input");
        uref_free(uref);
        return;
    }

    size_t samples;
    uint8_t sample_size;
    if (unlikely(!ubase_check(uref_sound_size(uref, &samples, &sample_size)))) {
        upipe_warn(upipe, "invalid sound buffer");
        uref_free(uref);
        return;
    }

    void *buf = NULL;
    const char *channel = NULL;
    if (upipe_filter_ebur128->planes == 1) {
        if (ubase_check(uref_sound_plane_iterate(uref, &channel)) && channel) {
            if (unlikely(!ubase_check(uref_sound_plane_read_void(uref,
                    channel, 0, -1, (const void **)&buf)))) {
                upipe_warn(upipe, "error mapping sound buffer");
                uref_free(uref);
                return;
            }
        }

    } else {
        buf = malloc(sample_size * upipe_filter_ebur128->channels * samples);
        if (buf == NULL) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(uref);
            return;
        }
        if (!ubase_check(uref_sound_interleave(uref, (uint8_t *)buf, 0,
                                               samples, sample_size,
                                               upipe_filter_ebur128->planes))) {
            upipe_warn(upipe, "error mapping sound buffer");
            uref_free(uref);
            return;
        }
    }

    if (unlikely((uintptr_t)buf & 1))
        upipe_warn(upipe, "unaligned buffer");

    switch (upipe_filter_ebur128->fmt) {
        case UPIPE_FILTER_EBUR128_SHORT:
            ebur128_add_frames_short(upipe_filter_ebur128->st, (short *)buf,
                                     samples);
            break;

        case UPIPE_FILTER_EBUR128_INT:
            ebur128_add_frames_int(upipe_filter_ebur128->st, (int *)buf,
                                   samples);
            break;

        case UPIPE_FILTER_EBUR128_FLOAT:
            ebur128_add_frames_float(upipe_filter_ebur128->st, (float *)buf,
                                     samples);
            break;

        case UPIPE_FILTER_EBUR128_DOUBLE:
            ebur128_add_frames_double(upipe_filter_ebur128->st, (double *)buf,
                                      samples);
            break;

        default:
            upipe_warn_va(upipe, "unknown sample format %d",
                          upipe_filter_ebur128->fmt);
            break;
    }

    if (upipe_filter_ebur128->planes == 1)
        uref_sound_plane_unmap(uref, channel, 0, -1);
    else
        free(buf);

    ebur128_loudness_momentary(upipe_filter_ebur128->st, &loud);
    ebur128_loudness_range(upipe_filter_ebur128->st, &lra);
    ebur128_loudness_global(upipe_filter_ebur128->st, &global);

    uref_ebur128_set_momentary(uref, loud);
    uref_ebur128_set_lra(uref, lra);
    uref_ebur128_set_global(uref, global);

    upipe_verbose_va(upipe, "loud %f lra %f global %f", loud, lra, global);

    upipe_filter_ebur128_output(upipe, uref, upump_p);
}
Example #20
0
/** @internal @This handles data.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure describing the picture
 * @param upump_p reference to pump that generated the buffer
 * @return true if the packet was handled
 */
static bool upipe_audiobar_handle(struct upipe *upipe, struct uref *uref,
                                  struct upump **upump_p)
{
    struct upipe_audiobar *upipe_audiobar = upipe_audiobar_from_upipe(upipe);
    const char *def;
    if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) {
        UBASE_FATAL(upipe,
                uref_sound_flow_get_channels(uref, &upipe_audiobar->channels))
        uref_sound_flow_clear_format(uref);
        UBASE_FATAL(upipe,
                uref_attr_import(uref, upipe_audiobar->flow_def_config))
        uref_pic_flow_clear_format(uref);
        UBASE_FATAL(upipe, uref_pic_flow_set_planes(uref, 0))
        UBASE_FATAL(upipe, uref_pic_flow_set_macropixel(uref, 1))
        UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 1, 1, 1, "y8"))
        UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 2, 1, 1, "u8"))
        UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 2, 1, 1, "v8"))
        UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 1, 1, 1, "a8"))
        UBASE_FATAL(upipe, uref_pic_set_progressive(uref))

        upipe_audiobar->hsize = upipe_audiobar->vsize =
            upipe_audiobar->sep_width = upipe_audiobar->pad_width = UINT64_MAX;
        upipe_audiobar_require_flow_format(upipe, uref);
        return true;
    }

    if (!upipe_audiobar->ubuf_mgr)
        return false;

    if (unlikely(upipe_audiobar->hsize == UINT64_MAX))
        return false;

    struct ubuf *ubuf = ubuf_pic_alloc(upipe_audiobar->ubuf_mgr,
                                       upipe_audiobar->hsize,
                                       upipe_audiobar->vsize);
    uref_attach_ubuf(uref, ubuf);

    uint8_t *dst[4];
    size_t strides[4];
    uint8_t hsubs[4];
    uint8_t vsubs[4];
    static const char *chroma[4] = { "y8", "u8", "v8", "a8" };
    for (int i = 0; i < 4; i++) {
        if (unlikely(!ubase_check(uref_pic_plane_write(uref, chroma[i],
                            0, 0, -1, -1, &dst[i])) ||
                     !ubase_check(uref_pic_plane_size(uref, chroma[i],
                             &strides[i], &hsubs[i], &vsubs[i], NULL)))) {
             upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
             uref_free(uref);
             return true;
        }
    }

    uint8_t alpha = upipe_audiobar->alpha;
    uint64_t h = upipe_audiobar->vsize;
    const int hred = h - (iec_scale(-8.) * h);
    const int hyellow = h - (iec_scale(-18.) * h);
    uint8_t transparent[4] = { 0x10, 0x80, 0x80, 0 };
    uint8_t black[4] = { 0x10, 0x80, 0x80, alpha };
    uint8_t red[2][4] = { { 76, 85, 0xff, alpha }, { 37, 106, 191, alpha } };
    uint8_t green[2][4] = { { 150, 44, 21, alpha }, { 74, 85, 74, alpha } };
    uint8_t yellow[2][4] = { { 226, 1, 148, alpha }, { 112, 64, 138, alpha } };

    uint64_t pts = 0;
    if (unlikely(!ubase_check(uref_clock_get_pts_prog(uref, &pts)))) {
        upipe_warn(upipe, "unable to read pts");
    }

    for (uint8_t chan = 0; chan < upipe_audiobar->channels; chan++) {
        double amplitude = 0.;
        if (unlikely(!ubase_check(uref_amax_get_amplitude(uref, &amplitude,
                                                          chan))))
            upipe_warn_va(upipe, "unable to get amplitude for channel %"PRIu8", assuming silence", chan);

        double scale = log10(amplitude) * 20;

        // IEC-268-18 return time speed is 20dB per 1.7s (+/- .3)
        if (upipe_audiobar->peak_date[chan])
            upipe_audiobar->peak[chan] -= 20 * (pts - upipe_audiobar->peak_date[chan]) / (1.7 * UCLOCK_FREQ);

        upipe_audiobar->peak_date[chan] = pts;

        if (scale >= upipe_audiobar->peak[chan]) /* higher than lowered peak */
            upipe_audiobar->peak[chan] = scale;
        else /* Current amplitude can not go below the lowered peak value */
            scale = upipe_audiobar->peak[chan];

        scale = iec_scale(scale);

        const int hmax = h - scale * h;
        for (int row = 0; row < h; row++) {
            bool bright = row > hmax;

            const uint8_t *color = row < hred ? red[!bright] :
                                   row < hyellow ? yellow[!bright] :
                                   green[!bright];

            copy_color(dst, strides, hsubs, vsubs, color, row,
                       chan * upipe_audiobar->chan_width,
                       upipe_audiobar->chan_width);
            if (chan && upipe_audiobar->sep_width)
                copy_color(dst, strides, hsubs, vsubs, black, row,
                           chan * upipe_audiobar->chan_width -
                           upipe_audiobar->sep_width / 2,
                           upipe_audiobar->sep_width);

            if (chan == upipe_audiobar->channels - 1 &&
                upipe_audiobar->pad_width)
                copy_color(dst, strides, hsubs, vsubs, transparent, row,
                           (chan + 1) * upipe_audiobar->chan_width,
                           upipe_audiobar->pad_width);
        }
    }

    /* dB marks */
    for (int i = 1; i <= 6; i++) {
        int row = h - (iec_scale(-10 * i) * h);
        copy_color(dst, strides, hsubs, vsubs, black, row, 0,
                   upipe_audiobar->hsize);
    }

    for (int i = 0; i < 4; i++)
        ubuf_pic_plane_unmap(ubuf, chroma[i], 0, 0, -1, -1);
    upipe_audiobar_output(upipe, uref, upump_p);
    return true;
}
Example #21
0
/** @internal @This handles packets.
 *
 * @param upipe description structure of the pipe
 * @param uref uref structure
 * @param upump upump structure
 */
static void upipe_avcdec_input_packet(struct upipe *upipe, struct uref *uref,
                              struct upump *upump)
{
    uint8_t *inbuf;
    size_t insize = 0;

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

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

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

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

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

    uref_pic_set_number(uref, upipe_avcdec->counter);

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

    upipe_avcdec_process_buf(upipe, inbuf, insize, upump);

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

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

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

    frame = upipe_avcdec->frame;

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

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

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

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

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

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

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

        default: {
            /* should never be here */
            upipe_err_va(upipe, "Unsupported media type (%d)",
                                    upipe_avcdec->context->codec->type);
            return false;
        }
    }
}
Example #23
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;
}
Example #24
0
/** @internal @This allocates a blank source pipe.
 *
 * @param mgr common management structure
 * @param uprobe structure used to raise events
 * @param signature signature of the pipe allocator
 * @param args optional arguments
 * @return pointer to upipe or NULL in case of allocation error
 */
static struct upipe *upipe_blksrc_alloc(struct upipe_mgr *mgr,
                                        struct uprobe *uprobe,
                                        uint32_t signature, va_list args)
{
    struct uref *flow_def;
    struct upipe *upipe = upipe_blksrc_alloc_flow(mgr, uprobe, signature, args,
                                                  &flow_def);
    if (unlikely(!upipe)) {
        return NULL;
    }

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

    upipe_throw_ready(upipe);

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

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

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

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

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

    upipe_blksrc_store_bin_input(upipe, src);

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

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

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

    upipe_blksrc_store_bin_output(upipe, blk);

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

    return upipe;
}
Example #25
0
/** @internal @This parses and removes the PES header of a packet.
 *
 * @param upipe description structure of the pipe
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_ts_pesd_decaps(struct upipe *upipe, struct upump **upump_p)
{
    struct upipe_ts_pesd *upipe_ts_pesd = upipe_ts_pesd_from_upipe(upipe);
    uint8_t buffer[PES_HEADER_SIZE];
    const uint8_t *pes_header = uref_block_peek(upipe_ts_pesd->next_uref,
                                                0, PES_HEADER_SIZE, buffer);
    if (unlikely(pes_header == NULL))
        return;

    bool validate = pes_validate(pes_header);
    uint8_t streamid = pes_get_streamid(pes_header);
    uint16_t length = pes_get_length(pes_header);
    UBASE_FATAL(upipe, uref_block_peek_unmap(upipe_ts_pesd->next_uref, 0,
                                             buffer, pes_header))

    if (unlikely(!validate)) {
        upipe_warn(upipe, "wrong PES header");
        upipe_ts_pesd_flush(upipe);
        return;
    }

    if (unlikely(streamid == PES_STREAM_ID_PADDING)) {
        upipe_ts_pesd_flush(upipe);
        return;
    }

    if (length)
        upipe_ts_pesd->next_pes_size = length + PES_HEADER_SIZE;
    else
        upipe_ts_pesd->next_pes_size = 0;

    if (streamid == PES_STREAM_ID_PSM ||
        streamid == PES_STREAM_ID_PRIVATE_2 ||
        streamid == PES_STREAM_ID_ECM ||
        streamid == PES_STREAM_ID_EMM ||
        streamid == PES_STREAM_ID_PSD ||
        streamid == PES_STREAM_ID_DSMCC ||
        streamid == PES_STREAM_ID_H222_1_E) {
        UBASE_FATAL(upipe, uref_block_resize(upipe_ts_pesd->next_uref,
                                             PES_HEADER_SIZE, -1))
        upipe_ts_pesd_check_output(upipe, upump_p);
        return;
    }

    if (unlikely(length != 0 && length < PES_HEADER_OPTIONAL_SIZE)) {
        upipe_warn(upipe, "wrong PES length");
        upipe_ts_pesd_flush(upipe);
        return;
    }

    uint8_t buffer2[PES_HEADER_SIZE_NOPTS - PES_HEADER_SIZE];
    pes_header = uref_block_peek(upipe_ts_pesd->next_uref, PES_HEADER_SIZE,
                                 PES_HEADER_OPTIONAL_SIZE, buffer2);
    if (unlikely(pes_header == NULL))
        return;

    validate = pes_validate_header(pes_header - PES_HEADER_SIZE);
    bool alignment = pes_get_dataalignment(pes_header - PES_HEADER_SIZE);
    bool has_pts = pes_has_pts(pes_header - PES_HEADER_SIZE);
    bool has_dts = pes_has_dts(pes_header - PES_HEADER_SIZE);
    uint8_t headerlength = pes_get_headerlength(pes_header - PES_HEADER_SIZE);
    UBASE_FATAL(upipe, uref_block_peek_unmap(upipe_ts_pesd->next_uref,
                PES_HEADER_SIZE, buffer2, pes_header))

    if (unlikely(!validate)) {
        upipe_warn(upipe, "wrong PES optional header");
        upipe_ts_pesd_flush(upipe);
        return;
    }

    if (unlikely((length != 0 &&
                  headerlength + PES_HEADER_OPTIONAL_SIZE > length) ||
                 (has_pts && headerlength < PES_HEADER_SIZE_PTS -
                                            PES_HEADER_SIZE_NOPTS) ||
                 (has_dts && headerlength < PES_HEADER_SIZE_PTSDTS -
                                            PES_HEADER_SIZE_NOPTS))) {
        upipe_warn(upipe, "wrong PES header length");
        upipe_ts_pesd_flush(upipe);
        return;
    }

    if (upipe_ts_pesd->next_uref_size < PES_HEADER_SIZE_NOPTS + headerlength)
        return;

    if (has_pts) {
        uint8_t buffer3[PES_HEADER_TS_SIZE * 2];
        uint64_t pts, dts;
        const uint8_t *ts_fields = uref_block_peek(upipe_ts_pesd->next_uref,
                PES_HEADER_SIZE_NOPTS, PES_HEADER_TS_SIZE * (has_dts ? 2 : 1),
                buffer3);
        if (unlikely(ts_fields == NULL)) {
            upipe_ts_pesd_flush(upipe);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }

        validate = pes_validate_pts(ts_fields - PES_HEADER_SIZE_NOPTS);
        pts = pes_get_pts(ts_fields - PES_HEADER_SIZE_NOPTS);
        if (has_dts) {
            validate = validate &&
                       pes_validate_dts(ts_fields - PES_HEADER_SIZE_NOPTS);
            dts = pes_get_dts(ts_fields - PES_HEADER_SIZE_NOPTS);
        } else
            dts = pts;
        UBASE_FATAL(upipe, uref_block_peek_unmap(upipe_ts_pesd->next_uref,
                                    PES_HEADER_SIZE_NOPTS, buffer3, ts_fields))

        if (unlikely(!validate)) {
            upipe_warn(upipe, "wrong PES timestamp syntax");
#if 0
            /* disable this because it is a common syntax error */
            upipe_ts_pesd_flush(upipe);
            return;
#endif
        }

        uint64_t dts_pts_delay = (POW2_33 + pts - dts) % POW2_33;
        if (dts_pts_delay > POW2_33 / 2) {
            upipe_warn_va(upipe, "invalid PTS field (%"PRIu64" < %"PRIu64")",
                          pts, dts);
            dts_pts_delay = 0;
        }
        dts_pts_delay *= UCLOCK_FREQ / 90000;
        dts *= UCLOCK_FREQ / 90000;
        uref_clock_set_dts_orig(upipe_ts_pesd->next_uref, dts);
        uref_clock_set_dts_pts_delay(upipe_ts_pesd->next_uref, dts_pts_delay);
        upipe_throw_clock_ts(upipe, upipe_ts_pesd->next_uref);
    }

    if (alignment)
        uref_flow_set_random(upipe_ts_pesd->next_uref);

    UBASE_FATAL(upipe, uref_block_resize(upipe_ts_pesd->next_uref,
                            PES_HEADER_SIZE_NOPTS + headerlength, -1))
    upipe_ts_pesd_check_output(upipe, upump_p);
}
Example #26
0
/** @internal @This handles the input uref.
 *
 * @param upipe description structure of the pipe
 * @param uref input uref
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_vblk_input(struct upipe *upipe,
                             struct uref *uref,
                             struct upump **upump_p)
{
    struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe);
    struct uref *flow_def = upipe_vblk->flow_def;
    struct uref *input_flow_def = upipe_vblk->input_flow_def;

    if (uref->ubuf) {
        upipe_vblk_output(upipe, uref, upump_p);
        return;
    }

    if (unlikely(!input_flow_def)) {
        upipe_warn(upipe, "no input flow definition");
        uref_free(uref);
        return;
    }

    if (unlikely(!flow_def)) {
        upipe_warn(upipe, "no output flow definition");
        uref_free(uref);
        return;
    }

    if (unlikely(!upipe_vblk->ubuf_mgr)) {
        upipe_warn(upipe, "no ubuf manager set");
        uref_free(uref);
        return;
    }

    if (unlikely(!upipe_vblk->ubuf)) {
        upipe_verbose(upipe, "allocate blank picture");

        uint64_t hsize, vsize;
        ubase_assert(uref_pic_flow_get_hsize(upipe_vblk->flow_def, &hsize));
        ubase_assert(uref_pic_flow_get_vsize(upipe_vblk->flow_def, &vsize));

        upipe_vblk->ubuf = ubuf_pic_alloc(upipe_vblk->ubuf_mgr, hsize, vsize);
        if (unlikely(!upipe_vblk->ubuf)) {
            upipe_err(upipe, "fail to allocate picture");
            uref_free(uref);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }
        ubuf_pic_clear(upipe_vblk->ubuf, 0, 0, -1, -1, 1);
    }

    struct ubuf *ubuf = ubuf_dup(upipe_vblk->ubuf);
    if (unlikely(!ubuf)) {
        upipe_err(upipe, "fail to duplicate blank picture");
        uref_free(uref);
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    uref_attach_ubuf(uref, ubuf);
    if (ubase_check(uref_pic_get_progressive(flow_def)))
        uref_pic_set_progressive(uref);

    upipe_vblk_output(upipe, uref, upump_p);
}
Example #27
0
/** @internal @This parses A/52 header.
 *
 * @param upipe description structure of the pipe
 * @return false in case the header is inconsistent
 */
static bool upipe_a52f_parse_a52(struct upipe *upipe)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    uint8_t header[A52_SYNCINFO_SIZE + 2];
    if (unlikely(!ubase_check(uref_block_extract(upipe_a52f->next_uref, 0,
                                                 sizeof(header), header))))
        return true; /* not enough data */

    ssize_t next_frame_size = a52_get_frame_size(a52_get_fscod(header),
                                                 a52_get_frmsizecod(header));
    if (!next_frame_size)
        return false;

    if (likely(a52_sync_compare_formats(header, upipe_a52f->sync_header) &&
               header[5] == upipe_a52f->sync_header[5] &&
               header[6] == upipe_a52f->sync_header[6])) {
        /* identical sync */
        upipe_a52f->next_frame_size = next_frame_size;
        return true;
    }

    /* sample rate */
    uint64_t samplerate;
    switch (a52_get_fscod(header)) {
        case A52_FSCOD_48KHZ:
            samplerate = 48000;
            break;
        case A52_FSCOD_441KHZ:
            samplerate = 44100;
            break;
        case A52_FSCOD_32KHZ:
            samplerate = 32000;
            break;
        default:
            upipe_warn(upipe, "reserved fscod");
            return false;
    }

    /* frame size */
    upipe_a52f->next_frame_size = next_frame_size;

    /* channels */
    int acmod = a52_get_acmod(header);
    int channels = acmod_chans[acmod].nfchans +
        ((header[6] >> (4 - acmod_chans[acmod].lfe_offset)) & 1);

    uint64_t octetrate = a52_bitrate_tab[a52_get_frmsizecod(header)] * 1000 / 8;
    memcpy(upipe_a52f->sync_header, header, A52_SYNCINFO_SIZE + 2);
    upipe_a52f->samplerate = samplerate;

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

    UBASE_FATAL(upipe, uref_flow_set_complete(flow_def))
    UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.ac3.sound."))
    UBASE_FATAL(upipe, uref_sound_flow_set_samples(flow_def, A52_FRAME_SAMPLES))
    UBASE_FATAL(upipe, uref_sound_flow_set_rate(flow_def, samplerate))
    UBASE_FATAL(upipe, uref_sound_flow_set_channels(flow_def, channels))
    UBASE_FATAL(upipe, uref_clock_set_latency(flow_def,
                upipe_a52f->input_latency +
                UCLOCK_FREQ * A52_FRAME_SAMPLES / samplerate))
    UBASE_FATAL(upipe, uref_block_flow_set_octetrate(flow_def, octetrate))

    flow_def = upipe_a52f_store_flow_def_attr(upipe, flow_def);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return false;
    }
    upipe_a52f_store_flow_def(upipe, flow_def);

    return true;
}
Example #28
0
/** @internal @This configures a new codec context
 *
 * @param upipe description structure of the pipe
 * @param codec avcodec description structure
 * @param extradata pointer to extradata buffer
 * @param extradata_size extradata size
 * @return false if the buffer couldn't be accepted
 */
static bool upipe_avcdec_open_codec(struct upipe *upipe, AVCodec *codec,
                                    uint8_t *extradata, int extradata_size)
{
    AVCodecContext *context = NULL;
    struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe);
    assert(upipe);

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

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

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

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

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

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

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

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

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

    upipe_release(upipe);
    return true;
}
Example #29
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 inline void upipe_rtpd_input(struct upipe *upipe, struct uref *uref,
                                    struct upump **upump_p)
{
    struct upipe_rtpd *upipe_rtpd = upipe_rtpd_from_upipe(upipe);
    uint8_t rtp_buffer[RTP_HEADER_SIZE];
    const uint8_t *rtp_header = uref_block_peek(uref, 0, RTP_HEADER_SIZE, 
                                                rtp_buffer);
    if (unlikely(rtp_header == NULL)) {
        upipe_warn(upipe, "invalid buffer received");
        uref_free(uref);
        return;
    }

    bool valid = rtp_check_hdr(rtp_header);
    bool extension = rtp_check_extension(rtp_header);
    uint8_t cc = rtp_get_cc(rtp_header);
    uint8_t type = rtp_get_type(rtp_header);
    uint16_t seqnum = rtp_get_seqnum(rtp_header);
    ptrdiff_t extension_offset = rtp_extension((uint8_t *)rtp_header) -
                                 rtp_header;
    uref_block_peek_unmap(uref, 0, rtp_buffer, rtp_header);

    if (unlikely(!valid)) {
        upipe_warn(upipe, "invalid RTP header");
        uref_free(uref);
        return;
    }

    size_t offset = RTP_HEADER_SIZE + 4 * cc;

    if (extension) {
        rtp_header = uref_block_peek(uref, extension_offset,
                                     RTP_EXTENSION_SIZE, rtp_buffer);
        if (unlikely(rtp_header == NULL)) {
            upipe_warn(upipe, "invalid buffer received");
            uref_free(uref);
            return;
        }
        offset += 4 * (1 + rtpx_get_length(rtp_header));
        uref_block_peek_unmap(uref, extension_offset, rtp_buffer, rtp_header);
    }

    if (unlikely(upipe_rtpd->expected_seqnum != -1 &&
                 seqnum != upipe_rtpd->expected_seqnum)) {
        upipe_warn_va(upipe, "potentially lost %d RTP packets",
                      (seqnum + UINT16_MAX + 1 - upipe_rtpd->expected_seqnum) &
                      UINT16_MAX);
        uref_flow_set_discontinuity(uref);
    }
    upipe_rtpd->expected_seqnum = seqnum + 1;
    upipe_rtpd->expected_seqnum &= UINT16_MAX;

    if (unlikely(type != upipe_rtpd->type)) {
        assert(upipe_rtpd->flow_def_input != NULL);
        struct uref *flow_def = uref_dup(upipe_rtpd->flow_def_input);
        if (unlikely(flow_def == NULL)) {
            uref_free(uref);
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            return;
        }

        switch (type) {
            case RTP_TYPE_TS:
                uref_flow_set_def(flow_def, "block.mpegtsaligned.");
                break;
            default:
                break;
        }
        upipe_rtpd->type = type;
        upipe_rtpd_store_flow_def(upipe, flow_def);
    }

    uref_block_resize(uref, offset, -1);
    upipe_rtpd_output(upipe, uref, upump_p);
}
Example #30
0
static void upipe_rtp_h264_drop(struct upipe *upipe, struct uref *uref)
{
    upipe_warn(upipe, "drop...");
    uref_free(uref);
}