/** @internal @This sets the input flow definition. * * @param upipe description structure of the pipe * @param flow_def flow definition packet * @return an error code */ static int upipe_a52f_set_flow_def(struct upipe *upipe, struct uref *flow_def) { if (flow_def == NULL) return UBASE_ERR_INVALID; const char *def; if (unlikely(!ubase_check(uref_flow_get_def(flow_def, &def)) || (ubase_ncmp(def, "block.ac3.") && ubase_ncmp(def, "block.eac3.") && strcmp(def, "block.")))) return UBASE_ERR_INVALID; struct uref *flow_def_dup; if (unlikely((flow_def_dup = uref_dup(flow_def)) == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } struct upipe_a52f *upipe_a52f = upipe_a52f_from_upipe(upipe); upipe_a52f->input_latency = 0; uref_clock_get_latency(flow_def, &upipe_a52f->input_latency); if (unlikely(upipe_a52f->samplerate && !ubase_check(uref_clock_set_latency(flow_def_dup, upipe_a52f->input_latency + UCLOCK_FREQ * A52_FRAME_SAMPLES / upipe_a52f->samplerate)))) upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); flow_def = upipe_a52f_store_flow_def_input(upipe, flow_def_dup); if (flow_def != NULL) upipe_a52f_store_flow_def(upipe, flow_def); return UBASE_ERR_NONE; }
/** @internal @This sets the input flow definition. * * @param upipe description structure of the pipe * @param flow_def flow definition packet * @return an error code */ static int upipe_agg_set_flow_def(struct upipe *upipe, struct uref *flow_def) { if (flow_def == NULL) return UBASE_ERR_INVALID; UBASE_RETURN(uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF)) struct upipe_agg *upipe_agg = upipe_agg_from_upipe(upipe); uint64_t size = 0; uref_block_flow_get_size(flow_def, &size); upipe_agg->input_size = size; uint64_t octetrate = 0; uref_block_flow_get_octetrate(flow_def, &octetrate); uint64_t latency = 0; uref_clock_get_latency(flow_def, &latency); struct uref *flow_def_dup; if ((flow_def_dup = uref_dup(flow_def)) == NULL) return UBASE_ERR_ALLOC; UBASE_RETURN(uref_block_flow_set_size(flow_def_dup, upipe_agg->output_size)) if (octetrate) { UBASE_RETURN(uref_clock_set_latency(flow_def_dup, latency + (uint64_t)upipe_agg->output_size * UCLOCK_FREQ / octetrate)) } upipe_agg_store_flow_def(upipe, flow_def_dup); return UBASE_ERR_NONE; }
/** @internal @This sets the input flow definition. * * @param upipe description structure of the pipe * @param flow_def flow definition packet * @return an error code */ static int upipe_nacl_audio_set_flow_def(struct upipe *upipe, struct uref *flow_def) { if (flow_def == NULL) return UBASE_ERR_INVALID; struct upipe_nacl_audio *upipe_nacl_audio = upipe_nacl_audio_from_upipe(upipe); UBASE_RETURN(uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF)) UBASE_RETURN(uref_sound_flow_match_rate(flow_def, SAMPLE_RATE, SAMPLE_RATE)) UBASE_RETURN(uref_sound_flow_match_channels(flow_def, 2, 2)) UBASE_RETURN(uref_sound_flow_match_planes(flow_def, 1, 1)) UBASE_RETURN(uref_sound_flow_check_channel(flow_def, "lr")) upipe_nacl_audio->latency = 0; uref_clock_get_latency(flow_def, &upipe_nacl_audio->latency); return UBASE_ERR_NONE; }
/** @internal @This merges the new access unit into a possibly existing * incomplete PES, and outputs the PES if possible. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer * @return false if the input must be blocked */ static bool upipe_ts_pese_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_ts_pese *upipe_ts_pese = upipe_ts_pese_from_upipe(upipe); const char *def; if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) { upipe_ts_pese_work(upipe, NULL); uref_ts_flow_get_pes_id(uref, &upipe_ts_pese->pes_id); upipe_ts_pese->pes_header_size = 0; uref_ts_flow_get_pes_header(uref, &upipe_ts_pese->pes_header_size); upipe_ts_pese->pes_min_duration = 0; uref_ts_flow_get_pes_min_duration(uref, &upipe_ts_pese->pes_min_duration); upipe_ts_pese->input_latency = 0; uref_clock_get_latency(uref, &upipe_ts_pese->input_latency); if (unlikely(!ubase_check(uref_clock_set_latency(uref, upipe_ts_pese->input_latency + upipe_ts_pese->pes_min_duration)))) upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); upipe_ts_pese_store_flow_def(upipe, NULL); upipe_ts_pese_require_ubuf_mgr(upipe, uref); return true; } if (upipe_ts_pese->flow_def == NULL) return false; uint64_t uref_duration = upipe_ts_pese->pes_min_duration; uref_clock_get_duration(uref, &uref_duration); size_t uref_size = 0; uref_block_size(uref, &uref_size); uref_block_delete_start(uref); ulist_add(&upipe_ts_pese->next_pes, uref_to_uchain(uref)); upipe_ts_pese->next_pes_duration += uref_duration; upipe_ts_pese->next_pes_size += uref_size; if (upipe_ts_pese->next_pes_duration >= upipe_ts_pese->pes_min_duration) upipe_ts_pese_work(upipe, upump_p); return true; }
/** @internal @This outputs data to the file sink. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer * @return true if the uref was processed */ static bool upipe_fsink_output(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_fsink *upipe_fsink = upipe_fsink_from_upipe(upipe); const char *def; if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) { uint64_t latency = 0; uref_clock_get_latency(uref, &latency); if (latency > upipe_fsink->latency) upipe_fsink->latency = latency; uref_free(uref); return true; } if (unlikely(upipe_fsink->fd == -1)) { uref_free(uref); upipe_warn(upipe, "received a buffer before opening a file"); return true; } if (likely(upipe_fsink->uclock == NULL)) goto write_buffer; uint64_t cr_sys = 0; if (unlikely(!ubase_check(uref_clock_get_cr_sys(uref, &cr_sys)))) { upipe_warn(upipe, "received non-dated buffer"); goto write_buffer; } uint64_t now = uclock_now(upipe_fsink->uclock); cr_sys += upipe_fsink->latency; if (unlikely(now < cr_sys)) { upipe_fsink_wait_upump(upipe, cr_sys - now, upipe_fsink_watcher); return false; } write_buffer: for ( ; ; ) { int iovec_count = uref_block_iovec_count(uref, 0, -1); if (unlikely(iovec_count == -1)) { uref_free(uref); upipe_warn(upipe, "cannot read ubuf buffer"); break; } if (unlikely(iovec_count == 0)) { uref_free(uref); break; } struct iovec iovecs[iovec_count]; if (unlikely(!ubase_check(uref_block_iovec_read(uref, 0, -1, iovecs)))) { uref_free(uref); upipe_warn(upipe, "cannot read ubuf buffer"); break; } ssize_t ret = writev(upipe_fsink->fd, iovecs, iovec_count); uref_block_iovec_unmap(uref, 0, -1, iovecs); if (unlikely(ret == -1)) { switch (errno) { case EINTR: continue; case EAGAIN: #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif upipe_fsink_poll(upipe); return false; case EBADF: case EFBIG: case EINVAL: case EIO: case ENOSPC: case EPIPE: default: break; } uref_free(uref); upipe_warn_va(upipe, "write error to %s (%m)", upipe_fsink->path); upipe_fsink_set_upump(upipe, NULL); upipe_throw_sink_end(upipe); return true; } size_t uref_size; if (ubase_check(uref_block_size(uref, &uref_size)) && uref_size == ret) { uref_free(uref); break; } uref_block_resize(uref, ret, -1); } return true; }