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

    uint8_t words[2];
    if (!ubase_check(uref_block_extract(upipe_a52f->next_uref,
                            upipe_a52f->next_frame_size, 2, words))) {
        /* not enough data */
        if (upipe_a52f->acquired) {/* avoid delaying packets unnecessarily */
            *ready_p = true;
        }
        return true;
    }
    if (words[0] != 0xb || words[1] != 0x77) {
        return false;
    }
    *ready_p = true;
    return true;
}
Exemple #3
0
/** @internal @This checks and parses a line of a m3u file.
 *
 * @param upipe description structure of the pipe
 * @param flow_def the current flow definition
 * @param uref pointer to uref carrying the line to parse
 * @return an error code
 */
static int upipe_m3u_reader_process_line(struct upipe *upipe,
                                         struct uref *flow_def,
                                         struct uref *uref)
{
    static const struct {
        const char *pfx;
        int (*cb)(struct upipe *, struct uref *, const char *);
    } ext_cb[] = {
        { "#EXTM3U", upipe_m3u_reader_process_m3u },
        { "#EXT-X-VERSION:", upipe_m3u_reader_process_version },
        { "#EXT-X-TARGETDURATION:", upipe_m3u_reader_process_target_duration },
        { "#EXT-X-PLAYLIST-TYPE:", upipe_m3u_reader_process_playlist_type },
        { "#EXTINF:", upipe_m3u_reader_process_extinf },
        { "#EXT-X-BYTERANGE:", upipe_m3u_reader_process_byte_range },
        { "#EXT-X-MEDIA:", upipe_m3u_reader_process_media },
        { "#EXT-X-STREAM-INF:", upipe_m3u_reader_ext_x_stream_inf },
        { "#EXT-X-MEDIA-SEQUENCE:", upipe_m3u_reader_ext_x_media_sequence },
        { "#EXT-X-ENDLIST", upipe_m3u_reader_ext_x_endlist },
        { "#EXT-X-KEY:", upipe_m3u_reader_key },
    };

    size_t block_size;
    UBASE_RETURN(uref_block_size(uref, &block_size));

    uint8_t buffer[block_size + 1];
    memset(buffer, 0, sizeof (buffer));
    UBASE_RETURN(uref_block_extract(uref, 0, block_size, buffer));

    char *line = (char *)buffer;
    /* remove end of line */
    if (strlen(line) && line[strlen(line) - 1] == '\n') {
        line[strlen(line) - 1] = '\0';
        if (strlen(line) && line[strlen(line) - 1] == '\r')
            line[strlen(line) - 1] = '\0';
    }

    if (!strlen(line))
        return UBASE_ERR_NONE;

    if (*line == '#') {
        for (unsigned i = 0; i < UBASE_ARRAY_SIZE(ext_cb); i++) {
            if (strncmp(line, ext_cb[i].pfx, strlen(ext_cb[i].pfx)))
                continue;

            return ext_cb[i].cb(upipe, flow_def,
                                line + strlen(ext_cb[i].pfx));
        }
        upipe_dbg_va(upipe, "ignore `%s'", line);
        return UBASE_ERR_NONE;
    }

    return upipe_m3u_reader_process_uri(upipe, flow_def, line);
}
Exemple #4
0
/** @internal @This scans for a sync word.
 *
 * @param upipe description structure of the pipe
 * @param dropped_p filled with the number of octets to drop before the sync
 * @return true if a sync word was found
 */
static bool upipe_a52f_scan(struct upipe *upipe, size_t *dropped_p)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    while (ubase_check(uref_block_scan(upipe_a52f->next_uref, dropped_p, 0xb))) {
        uint8_t word;
        if (!ubase_check(uref_block_extract(upipe_a52f->next_uref,
                                            *dropped_p + 1, 1, &word)))
            return false;

        if (word == 0x77)
            return true;
        (*dropped_p)++;
    }
    return false;
}
Exemple #5
0
/** @internal @This parses a new header.
 *
 * @param upipe description structure of the pipe
 * @return false in case the header is inconsistent
 */
static bool upipe_a52f_parse_header(struct upipe *upipe)
{
    struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe);
    uint8_t header[6];
    if (unlikely(!ubase_check(uref_block_extract(upipe_a52f->next_uref, 0,
                        sizeof(header), header))))
        return true;

    switch (a52_get_bsid(header)) {
        case A52_BSID_ANNEX_E:
            return upipe_a52f_parse_a52e(upipe);
        case A52_BSID:
        default:
            return upipe_a52f_parse_a52(upipe);
    }

    return false; /* never reached */
}
Exemple #6
0
/** @internal @This scans for a sync word.
 *
 * @param upipe description structure of the pipe
 * @param dropped_p filled with the number of octets to drop before the sync
 * @return true if a sync word was found
 */
static bool upipe_s337d_scan(struct upipe *upipe, size_t *dropped_p)
{
    struct upipe_s337d *upipe_s337d = upipe_s337d_from_upipe(upipe);
    while (ubase_check(uref_block_scan(upipe_s337d->next_uref, dropped_p,
                                       S337_PREAMBLE_A1))) {
        uint8_t preamble[3];
        if (!ubase_check(uref_block_extract(upipe_s337d->next_uref,
                        *dropped_p + 1, 3, preamble)))
            return false;

        if (preamble[0] == S337_PREAMBLE_A2 &&
            preamble[1] == S337_PREAMBLE_B1 &&
            preamble[2] == S337_PREAMBLE_B2)
            return true;
        (*dropped_p)++;
    }
    return false;
}
Exemple #7
0
static void upipe_rtp_h264_input(struct upipe *upipe,
                                struct uref *uref,
                                struct upump **upump_p)
{
    size_t bz = 0;
    if (!ubase_check(uref_block_size(uref, &bz))) {
        upipe_err(upipe, "fail to get uref block size");
        return upipe_rtp_h264_drop(upipe, uref);
    }

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

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

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

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

    uref_free(uref);
}
/** @internal @This takes the payload of a TS packet and finds PSI sections
 * inside 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_psim_input(struct upipe *upipe, struct uref *uref,
                                struct upump **upump_p)
{
    struct upipe_ts_psim *upipe_ts_psim = upipe_ts_psim_from_upipe(upipe);
    if (unlikely(ubase_check(uref_flow_get_discontinuity(uref))))
        upipe_ts_psim_flush(upipe);

    if (ubase_check(uref_block_get_start(uref))) {
        if (likely(upipe_ts_psim->acquired)) {
            /* just remove pointer_field */
            if (unlikely(!ubase_check(uref_block_resize(uref, 1, -1)))) {
                uref_free(uref);
                upipe_ts_psim_flush(upipe);
                return;
            }
        } else {
            /* jump to the start of the next section */
            uint8_t pointer_field;
            if (unlikely(!ubase_check(uref_block_extract(uref, 0, 1, &pointer_field)) ||
                         !ubase_check(uref_block_resize(uref, 1 + pointer_field, -1)))) {
                uref_free(uref);
                return;
            }
            upipe_ts_psim_sync_acquired(upipe);
        }
        uref_block_delete_start(uref);

    } else if (unlikely(upipe_ts_psim->next_uref == NULL)) {
        uref_free(uref);
        upipe_ts_psim_flush(upipe);
        return;
    }

    while (upipe_ts_psim_merge(upipe, uref, upump_p));
    uref_free(uref);
}
Exemple #9
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;
}
Exemple #10
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;
}
/** @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++;
}
Exemple #12
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;
}
Exemple #14
0
/** @internal @This handles input buffers.
 *
 * @param upipe description structure of the pipe
 * @param uref input buffer to handle
 * @param upump_p reference to the pump that generated the buffer
 */
static void upipe_dvbcsa_enc_input(struct upipe *upipe,
                                   struct uref *uref,
                                   struct upump **upump_p)
{
    struct upipe_dvbcsa_enc *upipe_dvbcsa_enc =
        upipe_dvbcsa_enc_from_upipe(upipe);
    struct upipe_dvbcsa_common *common =
        upipe_dvbcsa_enc_to_common(upipe_dvbcsa_enc);

    if (unlikely(!upipe_dvbcsa_enc->key))
        /* no key set, forward */
        return upipe_dvbcsa_enc_output(upipe, uref, upump_p);

    uint32_t ts_header_size = TS_HEADER_SIZE;
    uint8_t buf[TS_HEADER_SIZE];
    const uint8_t *ts_header = uref_block_peek(uref, 0, sizeof (buf), buf);
    if (unlikely(!ts_header)) {
        upipe_err(upipe, "fail to read ts header");
        uref_free(uref);
        return;
    }
    uint8_t scrambling = ts_get_scrambling(ts_header);
    bool has_payload = ts_has_payload(ts_header);
    bool has_adaptation = ts_has_adaptation(ts_header);
    uint16_t pid = ts_get_pid(ts_header);
    uref_block_peek_unmap(uref, 0, buf, ts_header);

    if (!has_payload || scrambling ||
        !upipe_dvbcsa_common_check_pid(common, pid))
        return upipe_dvbcsa_enc_output(upipe, uref, upump_p);

    if (unlikely(has_adaptation)) {
        uint8_t af_length;
        int ret = uref_block_extract(uref, ts_header_size, 1, &af_length);
        if (unlikely(!ubase_check(ret))) {
            upipe_err(upipe, "fail to extract adaptation field length");
            uref_free(uref);
            return;
        }
        if (unlikely(af_length >= 183)) {
            upipe_warn(upipe, "invalid adaptation field received");
            uref_free(uref);
            return;
        }
        ts_header_size += af_length + 1;
    }

    struct ubuf *ubuf = ubuf_block_copy(uref->ubuf->mgr, uref->ubuf, 0, -1);
    if (unlikely(!ubuf)) {
        upipe_err(upipe, "fail to allocate buffer");
        uref_free(uref);
        return;
    }
    uref_attach_ubuf(uref, ubuf);
    int size = -1;
    uint8_t *ts;
    int ret = ubuf_block_write(ubuf, 0, &size, &ts);
    if (unlikely(!ubase_check(ret))) {
        upipe_err(upipe, "fail to write buffer");
        uref_free(uref);
        return;
    }
    ts_set_scrambling(ts, 0x2);
    dvbcsa_encrypt(upipe_dvbcsa_enc->key,
                   ts + ts_header_size,
                   size - ts_header_size);
    return upipe_dvbcsa_enc_output(upipe, uref, upump_p);
}