Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
/** @internal @This works on a telx frame and outputs it.
 *
 * @param upipe description structure of the pipe
 * @param upump_p reference to pump that generated the buffer
 */
static void upipe_telxf_work(struct upipe *upipe, struct upump **upump_p)
{
    struct upipe_telxf *upipe_telxf = upipe_telxf_from_upipe(upipe);
    uint64_t octetrate =
        (upipe_telxf->next_uref_size * upipe_telxf->fps.num +
         upipe_telxf->fps.den - 1) / upipe_telxf->fps.den;
    if (octetrate != upipe_telxf->octetrate) {
        upipe_telxf->octetrate = octetrate;

        struct uref *flow_def = upipe_telxf_alloc_flow_def_attr(upipe);
        if (unlikely(flow_def == NULL)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(upipe_telxf->next_uref);
            goto upipe_telxf_work_err;
        }

        UBASE_FATAL(upipe, uref_pic_flow_set_fps(flow_def, upipe_telxf->fps))
        UBASE_FATAL(upipe, uref_block_flow_set_octetrate(flow_def,
                                upipe_telxf->octetrate))

        flow_def = upipe_telxf_store_flow_def_attr(upipe, flow_def);
        if (unlikely(flow_def == NULL)) {
            upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
            uref_free(upipe_telxf->next_uref);
            goto upipe_telxf_work_err;
        }
        upipe_telxf_store_flow_def(upipe, flow_def);
    }

    upipe_telxf_sync_acquired(upipe);

    uint64_t duration = UCLOCK_FREQ * upipe_telxf->fps.den /
                        upipe_telxf->fps.num;

    /* We work on encoded data so in the DTS domain. Rebase on DTS. */
    uint64_t date;
    struct urational drift_rate;
    drift_rate.den = 0;
    uref_clock_get_rate(upipe_telxf->next_uref, &drift_rate);
#define SET_DATE(dv)                                                        \
    if (ubase_check(uref_clock_get_dts_##dv(upipe_telxf->next_uref, &date)))\
        uref_clock_set_dts_##dv(&upipe_telxf->au_uref_s, date);             \
    if (ubase_check(uref_clock_get_dts_##dv(&upipe_telxf->au_uref_s,        \
                                            &date))) {                      \
        uref_clock_set_dts_##dv(upipe_telxf->next_uref, date);              \
        uref_clock_set_dts_##dv(&upipe_telxf->au_uref_s, date + duration);  \
    } else if (ubase_check(uref_clock_get_cr_##dv(upipe_telxf->next_uref,   \
                                                  &date))) {                \
        /* EN 300 472 Annex A */                                            \
        uref_clock_set_dts_##dv(upipe_telxf->next_uref,                     \
                                date + MAX_DELAY_TELX);                     \
        uref_clock_set_dts_##dv(&upipe_telxf->au_uref_s, date +             \
                                MAX_DELAY_TELX + duration);                 \
    }
    SET_DATE(sys)
    SET_DATE(prog)
    SET_DATE(orig)
#undef SET_DATE

    uref_clock_set_dts_pts_delay(upipe_telxf->next_uref, 0);
    if (drift_rate.den)
        uref_clock_set_rate(upipe_telxf->next_uref, drift_rate);

    upipe_telxf_output(upipe, upipe_telxf->next_uref, upump_p);
upipe_telxf_work_err:
    upipe_telxf->next_uref = NULL;
    upipe_telxf->next_uref_size = 0;
}
Ejemplo n.º 3
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);
}