/** @internal @This interpolates the PCRs for packets without a PCR. * * @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_pcr_interpolator_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_ts_pcr_interpolator *upipe_ts_pcr_interpolator = upipe_ts_pcr_interpolator_from_upipe(upipe); bool discontinuity = ubase_check(uref_flow_get_discontinuity(uref)); if (discontinuity) { upipe_ts_pcr_interpolator->last_pcr = 0; upipe_ts_pcr_interpolator->packets = 0; upipe_ts_pcr_interpolator->pcr_packets = 0; upipe_ts_pcr_interpolator->pcr_delta = 0; upipe_ts_pcr_interpolator->discontinuity = true; upipe_notice_va(upipe, "Clearing state"); } upipe_ts_pcr_interpolator->packets++; uint64_t pcr_prog = 0; uref_clock_get_cr_prog(uref, &pcr_prog); if (pcr_prog) { uint64_t delta = pcr_prog - upipe_ts_pcr_interpolator->last_pcr; upipe_ts_pcr_interpolator->last_pcr = pcr_prog; upipe_verbose_va(upipe, "pcr_prog %"PRId64" offset %"PRId64" stored offset %"PRIu64" bitrate %"PRId64" bps", pcr_prog, delta, upipe_ts_pcr_interpolator->pcr_delta, INT64_C(27000000) * upipe_ts_pcr_interpolator->packets * 188 * 8 / delta); if (upipe_ts_pcr_interpolator->pcr_delta) upipe_ts_pcr_interpolator->pcr_packets = upipe_ts_pcr_interpolator->packets; upipe_ts_pcr_interpolator->pcr_delta = delta; upipe_ts_pcr_interpolator->packets = 0; } else if (upipe_ts_pcr_interpolator->pcr_packets) { uint64_t offset = upipe_ts_pcr_interpolator->pcr_delta * upipe_ts_pcr_interpolator->packets / upipe_ts_pcr_interpolator->pcr_packets; uint64_t prog = upipe_ts_pcr_interpolator->last_pcr + offset; uref_clock_set_date_prog(uref, prog, UREF_DATE_CR); upipe_throw_clock_ts(upipe, uref); } if (!upipe_ts_pcr_interpolator->pcr_packets) { uref_free(uref); return; } if (upipe_ts_pcr_interpolator->discontinuity) { uref_flow_set_discontinuity(uref); upipe_ts_pcr_interpolator->discontinuity = false; } upipe_ts_pcr_interpolator_output(upipe, uref, upump_p); }
/** @internal @This handles and outputs a frame. * * @param upipe description structure of the pipe * @param upump_p reference to pump that generated the buffer */ static void upipe_a52f_output_frame(struct upipe *upipe, struct upump **upump_p) { struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe); struct uref au_uref_s = upipe_a52f->au_uref_s; struct urational drift_rate = upipe_a52f->drift_rate; /* From now on, PTS declaration only impacts the next frame. */ upipe_a52f_flush_dates(upipe); struct uref *uref = upipe_a52f_extract_uref_stream(upipe, upipe_a52f->next_frame_size); if (unlikely(uref == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } lldiv_t div = lldiv(A52_FRAME_SAMPLES * UCLOCK_FREQ + upipe_a52f->duration_residue, upipe_a52f->samplerate); uint64_t duration = div.quot; upipe_a52f->duration_residue = div.rem; /* We work on encoded data so in the DTS domain. Rebase on DTS. */ uint64_t date; #define SET_DATE(dv) \ if (ubase_check(uref_clock_get_dts_##dv(&au_uref_s, &date))) { \ uref_clock_set_dts_##dv(uref, date); \ uref_clock_set_dts_##dv(&upipe_a52f->au_uref_s, date + duration); \ } else if (ubase_check(uref_clock_get_dts_##dv(uref, &date))) \ uref_clock_set_date_##dv(uref, UINT64_MAX, UREF_DATE_NONE); SET_DATE(sys) SET_DATE(prog) SET_DATE(orig) #undef SET_DATE uref_clock_set_dts_pts_delay(uref, 0); if (drift_rate.den) uref_clock_set_rate(uref, drift_rate); else uref_clock_delete_rate(uref); UBASE_FATAL(upipe, uref_clock_set_duration(uref, duration)) if (upipe_a52f->got_discontinuity) uref_flow_set_discontinuity(uref); upipe_a52f->got_discontinuity = false; upipe_a52f_output(upipe, uref, upump_p); }
/** @internal @This handles data. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static inline void upipe_rtpd_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_rtpd *upipe_rtpd = upipe_rtpd_from_upipe(upipe); uint8_t rtp_buffer[RTP_HEADER_SIZE]; const uint8_t *rtp_header = uref_block_peek(uref, 0, RTP_HEADER_SIZE, rtp_buffer); if (unlikely(rtp_header == NULL)) { upipe_warn(upipe, "invalid buffer received"); uref_free(uref); return; } bool valid = rtp_check_hdr(rtp_header); bool extension = rtp_check_extension(rtp_header); uint8_t cc = rtp_get_cc(rtp_header); uint8_t type = rtp_get_type(rtp_header); uint16_t seqnum = rtp_get_seqnum(rtp_header); ptrdiff_t extension_offset = rtp_extension((uint8_t *)rtp_header) - rtp_header; uref_block_peek_unmap(uref, 0, rtp_buffer, rtp_header); if (unlikely(!valid)) { upipe_warn(upipe, "invalid RTP header"); uref_free(uref); return; } size_t offset = RTP_HEADER_SIZE + 4 * cc; if (extension) { rtp_header = uref_block_peek(uref, extension_offset, RTP_EXTENSION_SIZE, rtp_buffer); if (unlikely(rtp_header == NULL)) { upipe_warn(upipe, "invalid buffer received"); uref_free(uref); return; } offset += 4 * (1 + rtpx_get_length(rtp_header)); uref_block_peek_unmap(uref, extension_offset, rtp_buffer, rtp_header); } if (unlikely(upipe_rtpd->expected_seqnum != -1 && seqnum != upipe_rtpd->expected_seqnum)) { upipe_warn_va(upipe, "potentially lost %d RTP packets", (seqnum + UINT16_MAX + 1 - upipe_rtpd->expected_seqnum) & UINT16_MAX); uref_flow_set_discontinuity(uref); } upipe_rtpd->expected_seqnum = seqnum + 1; upipe_rtpd->expected_seqnum &= UINT16_MAX; if (unlikely(type != upipe_rtpd->type)) { assert(upipe_rtpd->flow_def_input != NULL); struct uref *flow_def = uref_dup(upipe_rtpd->flow_def_input); if (unlikely(flow_def == NULL)) { uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } switch (type) { case RTP_TYPE_TS: uref_flow_set_def(flow_def, "block.mpegtsaligned."); break; default: break; } upipe_rtpd->type = type; upipe_rtpd_store_flow_def(upipe, flow_def); } uref_block_resize(uref, offset, -1); upipe_rtpd_output(upipe, uref, upump_p); }