/** @internal @This receives data. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static void upipe_telxf_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_telxf *upipe_telxf = upipe_telxf_from_upipe(upipe); size_t uref_size; if (!ubase_check(uref_block_size(uref, &uref_size)) || !uref_size) { uref_free(uref); return; } bool end = ubase_check(uref_block_get_end(uref)); if (ubase_check(uref_block_get_start(uref))) { if (upipe_telxf->next_uref != NULL) upipe_telxf_work(upipe, upump_p); upipe_telxf->next_uref = uref; upipe_telxf->next_uref_size = uref_size; } else if (likely(upipe_telxf->next_uref != NULL)) { struct ubuf *ubuf = uref_detach_ubuf(uref); uref_free(uref); if (unlikely(!ubase_check(uref_block_append(upipe_telxf->next_uref, ubuf)))) { ubuf_free(ubuf); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } upipe_telxf->next_uref_size += uref_size; } else { uref_free(uref); return; } if (end) upipe_telxf_work(upipe, upump_p); }
/** @internal @This receives data. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static void upipe_agg_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_agg *upipe_agg = upipe_agg_from_upipe(upipe); size_t size = 0; const size_t output_size = upipe_agg->output_size; uref_block_size(uref, &size); /* check for invalid or too large size */ if (unlikely(size == 0 || size > output_size)) { upipe_warn_va(upipe, "received packet of invalid size: %zu (output_size == %zu)", size, output_size); uref_free(uref); return; } /* flush if incoming packet makes aggregated overflow */ if (upipe_agg->size + size > output_size) { upipe_agg_output(upipe, upipe_agg->aggregated, upump_p); upipe_agg->aggregated = NULL; } /* keep or attach incoming packet */ if (unlikely(!upipe_agg->aggregated)) { upipe_agg->aggregated = uref; upipe_agg->size = size; } else { struct ubuf *append = uref_detach_ubuf(uref); uref_free(uref); if (unlikely(!ubase_check(uref_block_append(upipe_agg->aggregated, append)))) { upipe_warn(upipe, "error appending packet"); ubuf_free(append); return; }; upipe_agg->size += size; } /* anticipate next packet size and flush now if necessary */ if (upipe_agg->input_size) size = upipe_agg->input_size; if (unlikely(upipe_agg->size + size > output_size)) { upipe_agg_output(upipe, upipe_agg->aggregated, upump_p); upipe_agg->aggregated = NULL; upipe_agg->size = 0; } }
/** @internal @This takes the payload of a TS packet, checks if it may * contain part of a PES header, and outputs 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_pesd_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_ts_pesd *upipe_ts_pesd = upipe_ts_pesd_from_upipe(upipe); size_t uref_size; if (unlikely(!ubase_check(uref_block_size(uref, &uref_size)))) { upipe_warn(upipe, "invalid PES chunk"); uref_free(uref); return; } if (ubase_check(uref_block_get_start(uref))) { if (unlikely(upipe_ts_pesd->next_uref != NULL)) { upipe_warn(upipe, "truncated PES header"); uref_free(upipe_ts_pesd->next_uref); } upipe_ts_pesd->next_uref = uref; upipe_ts_pesd->next_uref_size = uref_size; upipe_ts_pesd_decaps(upipe, upump_p); } else if (upipe_ts_pesd->next_uref != NULL) { struct ubuf *ubuf = uref_detach_ubuf(uref); uref_free(uref); if (unlikely(!ubase_check(uref_block_append(upipe_ts_pesd->next_uref, ubuf)))) { ubuf_free(ubuf); upipe_ts_pesd_flush(upipe); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } upipe_ts_pesd->next_uref_size += uref_size; upipe_ts_pesd_decaps(upipe, upump_p); } else if (likely(upipe_ts_pesd->acquired)) { upipe_ts_pesd->next_uref = uref; upipe_ts_pesd->next_uref_size += uref_size; upipe_ts_pesd_check_output(upipe, upump_p); } else uref_free(uref); }
/** @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 prepends a PES header to a logical unit. * * @param upipe description structure of the pipe * @param upump_p reference to pump that generated the buffer */ static void upipe_ts_pese_work(struct upipe *upipe, struct upump **upump_p) { struct upipe_ts_pese *upipe_ts_pese = upipe_ts_pese_from_upipe(upipe); if (ulist_empty(&upipe_ts_pese->next_pes)) return; uint64_t pts = UINT64_MAX, dts = UINT64_MAX; struct uref *uref = uref_from_uchain(ulist_pop(&upipe_ts_pese->next_pes)); size_t header_size; if (upipe_ts_pese->pes_id != PES_STREAM_ID_PRIVATE_2) { uref_clock_get_pts_prog(uref, &pts); uref_clock_get_dts_prog(uref, &dts); if (pts != UINT64_MAX) { if (dts != UINT64_MAX && ((pts / CLOCK_SCALE) % POW2_33) != ((dts / CLOCK_SCALE) % POW2_33)) header_size = PES_HEADER_SIZE_PTSDTS; else header_size = PES_HEADER_SIZE_PTS; } else header_size = PES_HEADER_SIZE_NOPTS; } else header_size = PES_HEADER_SIZE; if (header_size < upipe_ts_pese->pes_header_size) header_size = upipe_ts_pese->pes_header_size; struct ubuf *ubuf = ubuf_block_alloc(upipe_ts_pese->ubuf_mgr, header_size); if (unlikely(ubuf == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); goto upipe_ts_pese_work_err; } uint8_t *buffer; int size = -1; if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &size, &buffer)))) { ubuf_free(ubuf); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); goto upipe_ts_pese_work_err; } pes_init(buffer); pes_set_streamid(buffer, upipe_ts_pese->pes_id); size_t pes_length = upipe_ts_pese->next_pes_size + header_size - PES_HEADER_SIZE; if (pes_length > UINT16_MAX) { if (unlikely((upipe_ts_pese->pes_id & PES_STREAM_ID_VIDEO_MPEG) != PES_STREAM_ID_VIDEO_MPEG)) upipe_warn(upipe, "PES length > 65535 for a non-video stream"); pes_set_length(buffer, 0); } else pes_set_length(buffer, pes_length); if (upipe_ts_pese->pes_id != PES_STREAM_ID_PRIVATE_2) { pes_set_headerlength(buffer, header_size - PES_HEADER_SIZE_NOPTS); pes_set_dataalignment(buffer); if (pts != UINT64_MAX) { pes_set_pts(buffer, (pts / CLOCK_SCALE) % POW2_33); if (dts != UINT64_MAX && ((pts / CLOCK_SCALE) % POW2_33) != ((dts / CLOCK_SCALE) % POW2_33)) pes_set_dts(buffer, (dts / CLOCK_SCALE) % POW2_33); } } ubuf_block_unmap(ubuf, 0); struct ubuf *payload = uref_detach_ubuf(uref); uref_attach_ubuf(uref, ubuf); if (unlikely(!ubase_check(uref_block_append(uref, payload)))) { uref_free(uref); ubuf_free(payload); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } /* intended pass-through */ upipe_ts_pese_work_err: uref_block_set_start(uref); upipe_ts_pese_output(upipe, uref, upump_p); struct uchain *uchain; while ((uchain = ulist_pop(&upipe_ts_pese->next_pes)) != NULL) upipe_ts_pese_output(upipe, uref_from_uchain(uchain), upump_p); upipe_ts_pese->next_pes_size = 0; upipe_ts_pese->next_pes_duration = 0; }