/** @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); }
/** @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; }
/** @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 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, &litude, 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); }
/** @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; }