/** @internal @This interpolates the PCRs for packets without a PCR.
 *
 * @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_pcr_interpolator_input(struct upipe *upipe, struct uref *uref,
                                  struct upump **upump_p)
{
    struct upipe_ts_pcr_interpolator *upipe_ts_pcr_interpolator = upipe_ts_pcr_interpolator_from_upipe(upipe);
    bool discontinuity = ubase_check(uref_flow_get_discontinuity(uref));
    if (discontinuity) {
        upipe_ts_pcr_interpolator->last_pcr = 0;
        upipe_ts_pcr_interpolator->packets = 0;
        upipe_ts_pcr_interpolator->pcr_packets = 0;
        upipe_ts_pcr_interpolator->pcr_delta = 0;
        upipe_ts_pcr_interpolator->discontinuity = true;
        upipe_notice_va(upipe, "Clearing state");
    }

    upipe_ts_pcr_interpolator->packets++;

    uint64_t pcr_prog = 0;
    uref_clock_get_cr_prog(uref, &pcr_prog);

    if (pcr_prog) {
        uint64_t delta = pcr_prog - upipe_ts_pcr_interpolator->last_pcr;
        upipe_ts_pcr_interpolator->last_pcr = pcr_prog;

        upipe_verbose_va(upipe,
                "pcr_prog %"PRId64" offset %"PRId64" stored offset %"PRIu64" bitrate %"PRId64" bps",
                pcr_prog, delta,
                upipe_ts_pcr_interpolator->pcr_delta,
                INT64_C(27000000) * upipe_ts_pcr_interpolator->packets * 188 * 8 / delta);

        if (upipe_ts_pcr_interpolator->pcr_delta)
            upipe_ts_pcr_interpolator->pcr_packets = upipe_ts_pcr_interpolator->packets;

        upipe_ts_pcr_interpolator->pcr_delta = delta;
        upipe_ts_pcr_interpolator->packets = 0;
    } else if (upipe_ts_pcr_interpolator->pcr_packets) {
        uint64_t offset = upipe_ts_pcr_interpolator->pcr_delta *
                    upipe_ts_pcr_interpolator->packets / upipe_ts_pcr_interpolator->pcr_packets;
        uint64_t prog = upipe_ts_pcr_interpolator->last_pcr + offset;
        uref_clock_set_date_prog(uref, prog, UREF_DATE_CR);
        upipe_throw_clock_ts(upipe, uref);
    }

    if (!upipe_ts_pcr_interpolator->pcr_packets) {
        uref_free(uref);
        return;
    }

    if (upipe_ts_pcr_interpolator->discontinuity) {
        uref_flow_set_discontinuity(uref);
        upipe_ts_pcr_interpolator->discontinuity = false;
    }
    upipe_ts_pcr_interpolator_output(upipe, uref, upump_p);
}
示例#2
0
/** @internal @This handles and outputs a frame.
 *
 * @param upipe description structure of the pipe
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_a52f_output_frame(struct upipe *upipe, struct upump **upump_p)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);

    struct uref au_uref_s = upipe_a52f->au_uref_s;
    struct urational drift_rate = upipe_a52f->drift_rate;
    /* From now on, PTS declaration only impacts the next frame. */
    upipe_a52f_flush_dates(upipe);

    struct uref *uref = upipe_a52f_extract_uref_stream(upipe,
            upipe_a52f->next_frame_size);
    if (unlikely(uref == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    lldiv_t div = lldiv(A52_FRAME_SAMPLES * UCLOCK_FREQ +
                        upipe_a52f->duration_residue,
                        upipe_a52f->samplerate);
    uint64_t duration = div.quot;
    upipe_a52f->duration_residue = div.rem;

    /* We work on encoded data so in the DTS domain. Rebase on DTS. */
    uint64_t date;
#define SET_DATE(dv)                                                        \
    if (ubase_check(uref_clock_get_dts_##dv(&au_uref_s, &date))) {          \
        uref_clock_set_dts_##dv(uref, date);                                \
        uref_clock_set_dts_##dv(&upipe_a52f->au_uref_s, date + duration);   \
    } else if (ubase_check(uref_clock_get_dts_##dv(uref, &date)))           \
        uref_clock_set_date_##dv(uref, UINT64_MAX, UREF_DATE_NONE);
    SET_DATE(sys)
    SET_DATE(prog)
    SET_DATE(orig)
#undef SET_DATE

    uref_clock_set_dts_pts_delay(uref, 0);
    if (drift_rate.den)
        uref_clock_set_rate(uref, drift_rate);
    else
        uref_clock_delete_rate(uref);

    UBASE_FATAL(upipe, uref_clock_set_duration(uref, duration))

    if (upipe_a52f->got_discontinuity)
        uref_flow_set_discontinuity(uref);
    upipe_a52f->got_discontinuity = false;
    upipe_a52f_output(upipe, uref, upump_p);
}
示例#3
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);
}