/** @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); }
/** @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; }
/** @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); }
/** @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; }
/** @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 */ }
/** @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; }
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); }
/** @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; }
/** @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++; }
/** @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; }
/** @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); }