Beispiel #1
0
/** @internal @This provides a flow format suggestion.
 *
 * @param upipe description structure of the pipe
 * @param request description structure of the request
 * @return an error code
 */
static int upipe_filter_ebur128_provide_flow_format(struct upipe *upipe,
                                                    struct urequest *request)
{
    const char *def;
    UBASE_RETURN(uref_flow_get_def(request->uref, &def))
    struct uref *flow = uref_dup(request->uref);
    UBASE_ALLOC_RETURN(flow);

    if (!ubase_ncmp(def, "sound.u8."))
        UBASE_FATAL(upipe, uref_flow_set_def(flow, "sound.s16."));

    return urequest_provide_flow_format(request, flow);
}
/** @internal @This provides a flow format suggestion.
 *
 * @param upipe description structure of the pipe
 * @param request description structure of the request
 * @return an error code
 */
static int upipe_filter_ebur128_provide_flow_format(struct upipe *upipe,
                                                    struct urequest *request)
{
    struct uref *flow = uref_dup(request->uref);
    UBASE_ALLOC_RETURN(flow);

    uint8_t planes;
    if (ubase_check(uref_sound_flow_get_planes(request->uref, &planes))
                                                         && planes != 1) {
        /* compute sample size */
        uint8_t sample_size = 0;
        uref_sound_flow_get_sample_size(request->uref, &sample_size);
        sample_size *= planes;

        /* construct packed channel name from planar names */
        char packed_channel[planes+1];
        uint8_t plane;
        for (plane=0; plane < planes; plane++) {
            const char *planar_channel = "";
            uref_sound_flow_get_channel(request->uref, &planar_channel, plane);
            packed_channel[plane] = *planar_channel;
        }
        packed_channel[planes] = '\0';

        /* set attributes */
        uref_sound_flow_clear_format(flow);
        UBASE_FATAL(upipe, uref_sound_flow_set_channels(flow, planes));
        UBASE_FATAL(upipe, uref_sound_flow_set_sample_size(flow, sample_size));
        UBASE_FATAL(upipe, uref_sound_flow_set_channel(flow,
                                                       packed_channel, 0));
        UBASE_FATAL(upipe, uref_sound_flow_set_planes(flow, 1));
    }

    UBASE_FATAL(upipe, uref_flow_set_def(flow, "sound.s16."));

    return urequest_provide_flow_format(request, flow);
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
/** @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);
}
Beispiel #8
0
/** @internal @This parses a new s337 header.
 *
 * @param upipe description structure of the pipe
 */
static void upipe_s337d_parse_preamble(struct upipe *upipe)
{
    struct upipe_s337d *upipe_s337d = upipe_s337d_from_upipe(upipe);
    uint8_t preamble[S337_PREAMBLE_SIZE];
    if (!ubase_check(uref_block_extract(upipe_s337d->next_uref, 0,
                    S337_PREAMBLE_SIZE, preamble)))
        return; /* not enough data */

    uint8_t data_type = s337_get_data_type(preamble);
    uint8_t data_mode = s337_get_data_mode(preamble);
    bool error = s337_get_error(preamble);
    uint8_t data_stream = s337_get_data_stream(preamble);
    uint8_t data_type_dep = s337_get_data_type_dep(preamble);
    upipe_s337d->next_frame_size = s337_get_length(preamble) + 7;
    upipe_s337d->next_frame_size /= 8;

    if (data_type != S337_TYPE_A52 && data_type != S337_TYPE_A52E) {
        upipe_s337d->next_frame_discard = true;
        return;
    }

    if (data_mode != S337_MODE_16) {
        upipe_err_va(upipe, "unsupported data mode (%"PRIu8")", data_mode);
        upipe_s337d->next_frame_discard = true;
        return;
    }

    upipe_s337d->next_frame_discard = false;
    if (error)
        upipe_warn(upipe, "error flag set");

    if (upipe_s337d->data_stream != data_stream) {
        upipe_dbg_va(upipe, "now following stream %"PRIu8, data_stream);
        upipe_s337d->data_stream = data_stream;
    }

    if (upipe_s337d->data_type == data_type)
        return;
    upipe_s337d->data_type = data_type;

    if (data_type_dep & S337_TYPE_A52_REP_RATE_FLAG)
        upipe_warn(upipe, "repetition rate flag set");
    if (data_type_dep & S337_TYPE_A52_NOT_FULL_SVC)
        upipe_warn(upipe, "not full service flag set");

    struct uref *flow_def = upipe_s337d_alloc_flow_def_attr(upipe);
    if (unlikely(flow_def == NULL)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }

    if (data_type == S337_TYPE_A52)
        UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.ac3.sound."))
    else
        UBASE_FATAL(upipe, uref_flow_set_def(flow_def, "block.eac3.sound."))

    flow_def = upipe_s337d_store_flow_def_attr(upipe, flow_def);
    if (unlikely(!flow_def)) {
        upipe_throw_fatal(upipe, UBASE_ERR_ALLOC);
        return;
    }
    upipe_s337d_store_flow_def(upipe, flow_def);
}
/** @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;
}