/** @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 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_s337_encaps_set_flow_def(struct upipe *upipe, struct uref *flow_def) { if (flow_def == NULL) return UBASE_ERR_INVALID; const char *def; UBASE_RETURN(uref_flow_get_def(flow_def, &def)) uint64_t rate; UBASE_RETURN(uref_sound_flow_get_rate(flow_def, &rate)) if (ubase_ncmp(def, EXPECTED_FLOW_DEF)) return UBASE_ERR_INVALID; struct uref *flow_def_dup = uref_dup(flow_def); if (flow_def_dup == NULL) return UBASE_ERR_ALLOC; uref_flow_set_def(flow_def_dup, "sound.s32.s337.a52."); uref_sound_flow_set_channels(flow_def_dup, 2); uref_sound_flow_set_sample_size(flow_def_dup, 2*4); if (!ubase_check(uref_sound_flow_add_plane(flow_def_dup, "lr")) || !ubase_check(uref_sound_flow_set_rate(flow_def_dup, rate))) { uref_free(flow_def_dup); return UBASE_ERR_ALLOC; } upipe_s337_encaps_require_ubuf_mgr(upipe, flow_def_dup); return UBASE_ERR_NONE; }
/** @internal @This is called when there is new data. * * @param upipe description structure of the pipe * @param uref uref carrying the data * @param upump_p reference to pump that generated the buffer */ static void upipe_m3u_reader_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_m3u_reader *upipe_m3u_reader = upipe_m3u_reader_from_upipe(upipe); if (ubase_check(uref_block_get_start(uref))) upipe_m3u_reader->restart = true; if (upipe_m3u_reader->restart) { upipe_m3u_reader_flush(upipe); upipe_m3u_reader->restart = false; } bool end = false; if (unlikely(ubase_check(uref_block_get_end(uref)))) end = true; upipe_m3u_reader_append_uref_stream(upipe, uref); upipe_m3u_reader_process(upipe); if (unlikely(end)) { upipe_m3u_reader_output_all(upipe, upump_p); upipe_m3u_reader->restart = true; } }
/** @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_s337d_set_flow_def(struct upipe *upipe, struct uref *flow_def) { if (flow_def == NULL) return UBASE_ERR_INVALID; const char *def; uint64_t rate; if (unlikely(!ubase_check(uref_flow_get_def(flow_def, &def)) || (ubase_ncmp(def, "block.s337.") && strcmp(def, "block.")) || !ubase_check(uref_sound_flow_get_rate(flow_def, &rate)))) 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_s337d *upipe_s337d = upipe_s337d_from_upipe(upipe); upipe_s337d->sample_rate = rate; flow_def = upipe_s337d_store_flow_def_input(upipe, flow_def_dup); if (flow_def != NULL) upipe_s337d_store_flow_def(upipe, flow_def); return UBASE_ERR_NONE; }
/** @internal @This parses and outputs a m3u file. * * @param upipe description structure of the pipe * @return an error code */ static void upipe_m3u_reader_process(struct upipe *upipe) { struct upipe_m3u_reader *upipe_m3u_reader = upipe_m3u_reader_from_upipe(upipe); if (unlikely(upipe_m3u_reader->current_flow_def == NULL)) { upipe_m3u_reader->current_flow_def = uref_dup(upipe_m3u_reader->flow_def); if (unlikely(upipe_m3u_reader->current_flow_def == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } } /* parse m3u */ int ret = UBASE_ERR_NONE; struct uref *uref = upipe_m3u_reader->next_uref; for (size_t offset = 0; uref && ubase_check(ret) && ubase_check(uref_block_scan(uref, &offset, '\n')); offset = 0, uref = upipe_m3u_reader->next_uref) { struct uref *line = upipe_m3u_reader_extract_uref_stream(upipe, offset + 1); ret = upipe_m3u_reader_process_line( upipe, upipe_m3u_reader->current_flow_def, line); uref_free(line); } if (!ubase_check(ret)) upipe_err(upipe, "invalid m3u"); }
/** @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 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 flow definition packet * @return an error code */ static int upipe_filter_ebur128_set_flow_def(struct upipe *upipe, struct uref *flow) { struct upipe_filter_ebur128 *upipe_filter_ebur128 = upipe_filter_ebur128_from_upipe(upipe); if (flow == NULL) return UBASE_ERR_INVALID; UBASE_RETURN(uref_flow_match_def(flow, "sound.s16.")) uint8_t channels, planes; uint64_t rate; if (unlikely(!ubase_check(uref_sound_flow_get_rate(flow, &rate)) || !ubase_check(uref_sound_flow_get_channels(flow, &channels)) || !ubase_check(uref_sound_flow_get_planes(flow, &planes)) || planes != 1)) { return UBASE_ERR_INVALID; } struct uref *flow_dup; if (unlikely((flow_dup = uref_dup(flow)) == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } if (unlikely(upipe_filter_ebur128->st)) { //ebur128_destroy(&upipe_filter_ebur128->st); ebur128_change_parameters(upipe_filter_ebur128->st, channels, rate); } else { upipe_filter_ebur128->st = ebur128_init(channels, rate, EBUR128_MODE_LRA | EBUR128_MODE_I | EBUR128_MODE_HISTOGRAM); } upipe_filter_ebur128_store_flow_def(upipe, flow_dup); return UBASE_ERR_NONE; }
/* iterate in es configuration options */ static bool es_conf_iterate(struct es_conf *conf, const char **key, const char **value, enum udict_type *type) { if (!ubase_check(udict_iterate(conf->options, key, type)) || *type == UDICT_TYPE_END) { return false; } return ubase_check(udict_get_string(conf->options, value, *type, *key)); }
static bool upipe_dveo_asi_sink_write(struct upipe *upipe, struct uref *uref, bool *reset_first_timestamp) { struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe); for (;;) { int iovec_count = uref_block_iovec_count(uref, 0, -1); if (unlikely(iovec_count == -1)) { upipe_warn(upipe, "cannot read ubuf buffer"); break; } if (unlikely(iovec_count == 0)) { break; } struct iovec iovecs[iovec_count]; if (unlikely(!ubase_check(uref_block_iovec_read(uref, 0, -1, iovecs)))) { upipe_warn(upipe, "cannot read ubuf buffer"); break; } ssize_t ret = writev(upipe_dveo_asi_sink->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_notice_va(upipe, "polling"); upipe_dveo_asi_sink_poll(upipe); return false; default: break; } upipe_warn_va(upipe, "write error to device %d (%m)", upipe_dveo_asi_sink->card_idx); upipe_dveo_asi_sink_set_upump(upipe, NULL); upipe_throw_sink_end(upipe); break; } size_t uref_size; if (ubase_check(uref_block_size(uref, &uref_size)) && uref_size == ret) { /* wrote succeeded */ *reset_first_timestamp = false; break; } uref_block_resize(uref, ret, -1); } return true; }
static bool upipe_dveo_asi_sink_add_header(struct upipe *upipe, struct uref *uref, uint64_t pts) { struct upipe_dveo_asi_sink *upipe_dveo_asi_sink = upipe_dveo_asi_sink_from_upipe(upipe); uint64_t hdr_size; if (!ubase_check(uref_block_get_header_size(uref, &hdr_size))) hdr_size = 0; if (hdr_size != 0) return false; /* alloc header */ struct ubuf *header = ubuf_block_alloc(uref->ubuf->mgr, 8); if (unlikely(!header)) { return true; } /* 63-bits timestamp */ union { uint8_t timestamp[8]; uint64_t pts; } timestamp; timestamp.pts = pts; if (upipe_dveo_asi_sink->first_timestamp) { upipe_dveo_asi_sink->first_timestamp = false; // FIXME: set the counter in an empty packet, and account for latency timestamp.pts |= 1LLU << 63; /* Set MSB = Set the counter */ } /* write header, 64 bits little-endian : * https://github.com/kierank/dveo-linux-master/blob/450e4b9e4292c2f71acd4d3d2e0a0cd0879d473a/doc/ASI/features.txt#L62 */ int size = 8; uint8_t *header_write_ptr; if (!ubase_check(ubuf_block_write(header, 0, &size, &header_write_ptr))) { upipe_err(upipe, "could not write header"); ubuf_free(header); return true; } memcpy(header_write_ptr, timestamp.timestamp, 8); uref_block_unmap(uref, 0); /* append payload (current ubuf) to header to form segmented ubuf */ struct ubuf *payload = uref_detach_ubuf(uref); if (unlikely(!ubase_check(ubuf_block_append(header, payload)))) { upipe_warn(upipe, "could not append payload to header"); ubuf_free(header); ubuf_free(payload); return true; } uref_attach_ubuf(uref, header); uref_block_set_header_size(uref, 8); return false; }
/** @internal @This handles input. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static void upipe_htons_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct ubuf *ubuf; size_t size = 0; int remain, bufsize = -1, offset = 0; uint8_t *buf = NULL; /* block size */ if (unlikely(!ubase_check(uref_block_size(uref, &size)))) { upipe_warn(upipe, "could not read uref block size"); uref_free(uref); return; } /* copy ubuf if shared or not 16b-unaligned or segmented */ bufsize = -1; if (!ubase_check(uref_block_write(uref, 0, &bufsize, &buf)) || ((uintptr_t)buf & 1) || bufsize != size) { ubuf = ubuf_block_copy(uref->ubuf->mgr, uref->ubuf, 0, size); if (unlikely(!ubuf)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); uref_free(uref); return; } uref_attach_ubuf(uref, ubuf); } else { uref_block_unmap(uref, 0); } /* process ubuf chunks */ while (size > 0) { bufsize = -1; if (unlikely(!ubase_check(uref_block_write(uref, offset, &bufsize, &buf)))) { upipe_warn(upipe, "unexpected buffer error"); uref_free(uref); return; } if (unlikely((uintptr_t)buf & 1)) { upipe_warn_va(upipe, "unaligned buffer: %p", buf); } for (remain = bufsize; remain > 1; remain -= 2) { *(uint16_t *)buf = htons(*(uint16_t *)buf); buf += 2; } uref_block_unmap(uref, offset); offset += bufsize; size -= bufsize; } upipe_htons_output(upipe, uref, upump_p); }
/** @internal @This catches events of the avcdec. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_avcdec(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_avcdec_s); struct uref *flow_def = va_arg(args, struct uref *); struct upipe *deint = upipe_void_alloc_output(upipe, glxplayer->upipe_filter_blend_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "deint")); if (unlikely(deint == NULL)) return UBASE_ERR_ALLOC; struct uref *output_flow = uref_dup(flow_def); if (unlikely(output_flow == NULL)) return UBASE_ERR_ALLOC; uref_pic_flow_clear_format(output_flow); if (unlikely(!ubase_check(uref_pic_flow_set_macropixel(output_flow, 1)) || !ubase_check(uref_pic_flow_set_planes(output_flow, 0)) || !ubase_check(uref_pic_flow_add_plane(output_flow, 1, 1, 3, "r8g8b8")))) { uref_free(output_flow); return UBASE_ERR_ALLOC; } struct upipe *yuvrgb = upipe_flow_alloc_output(deint, glxplayer->upipe_sws_mgr, uprobe_pfx_alloc_va(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "rgb"), output_flow); assert(yuvrgb != NULL); uref_free(output_flow); upipe_release(deint); glxplayer->upipe_glx_qsink = upipe_qsink_alloc(glxplayer->upipe_qsink_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "glx qsink"), glxplayer->upipe_glx_qsrc); if (unlikely(glxplayer->upipe_glx_qsink == NULL)) return UBASE_ERR_ALLOC; upipe_set_output(yuvrgb, glxplayer->upipe_glx_qsink); upipe_release(yuvrgb); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** @internal @This sets the input flow definition. * * @param upipe description structure of the pipe * @param flow flow definition packet * @return an error code */ static int upipe_filter_ebur128_set_flow_def(struct upipe *upipe, struct uref *flow) { struct upipe_filter_ebur128 *upipe_filter_ebur128 = upipe_filter_ebur128_from_upipe(upipe); if (flow == NULL) return UBASE_ERR_INVALID; enum upipe_filter_ebur128_fmt fmt; const char *def; UBASE_RETURN(uref_flow_get_def(flow, &def)) if (!ubase_ncmp(def, "sound.s16.")) fmt = UPIPE_FILTER_EBUR128_SHORT; else if (!ubase_ncmp(def, "sound.s32.")) fmt = UPIPE_FILTER_EBUR128_INT; else if (!ubase_ncmp(def, "sound.f32.")) fmt = UPIPE_FILTER_EBUR128_FLOAT; else if (!ubase_ncmp(def, "sound.f64.")) fmt = UPIPE_FILTER_EBUR128_DOUBLE; else return UBASE_ERR_INVALID; uint64_t rate; if (unlikely(!ubase_check(uref_sound_flow_get_rate(flow, &rate)) || !ubase_check(uref_sound_flow_get_channels(flow, &upipe_filter_ebur128->channels)) || !ubase_check(uref_sound_flow_get_planes(flow, &upipe_filter_ebur128->planes)))) return UBASE_ERR_INVALID; struct uref *flow_dup; if (unlikely((flow_dup = uref_dup(flow)) == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } upipe_filter_ebur128->fmt = fmt; if (unlikely(upipe_filter_ebur128->st)) { //ebur128_destroy(&upipe_filter_ebur128->st); ebur128_change_parameters(upipe_filter_ebur128->st, upipe_filter_ebur128->channels, rate); } else { upipe_filter_ebur128->st = ebur128_init(upipe_filter_ebur128->channels, rate, EBUR128_MODE_LRA | EBUR128_MODE_I | EBUR128_MODE_HISTOGRAM); } upipe_filter_ebur128_store_flow_def(upipe, flow_dup); return UBASE_ERR_NONE; }
/** @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 allocates a video blank pipe. * * @param mgr pointer to upipe manager * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return an allocated pipe */ static struct upipe *upipe_vblk_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct uref *flow_def; struct upipe *upipe = upipe_vblk_alloc_flow(mgr, uprobe, signature, args, &flow_def); if (unlikely(!upipe)) { return NULL; } upipe_vblk_init_urefcount(upipe); upipe_vblk_init_output(upipe); upipe_vblk_init_flow_def(upipe); upipe_vblk_init_ubuf_mgr(upipe); struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe); upipe_vblk->ubuf = NULL; upipe_throw_ready(upipe); if (unlikely(!ubase_check(upipe_vblk_check_flow_def(upipe, flow_def)))) { uref_free(flow_def); upipe_release(upipe); return NULL; } upipe_vblk_store_flow_def(upipe, flow_def); return upipe; }
static void pic_fill_in(struct ubuf *ubuf) { size_t hsize, vsize; uint8_t macropixel; ubase_assert(ubuf_pic_size(ubuf, &hsize, &vsize, ¯opixel)); const char *chroma = NULL; while (ubase_check(ubuf_pic_plane_iterate(ubuf, &chroma)) && chroma != NULL) { size_t stride; uint8_t hsub, vsub, macropixel_size; ubase_assert(ubuf_pic_plane_size(ubuf, chroma, &stride, &hsub, &vsub, ¯opixel_size)); int hoctets = hsize * macropixel_size / hsub / macropixel; uint8_t *buffer; ubase_assert(ubuf_pic_plane_write(ubuf, chroma, 0, 0, -1, -1, &buffer)); for (int y = 0; y < vsize / vsub; y++) { for (int x = 0; x < hoctets; x++) buffer[x] = 1 + (y * hoctets) + x; buffer += stride; } ubase_assert(ubuf_pic_plane_unmap(ubuf, chroma, 0, 0, -1, -1)); } }
/* add option to es configuration */ static bool es_conf_add_option(struct es_conf *conf, const char *key, const char *value) { assert(conf); return ubase_check(udict_set_string(conf->options, value, UDICT_TYPE_STRING, key)); }
static void upipe_rtp_opus_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_rtp_opus *upipe_rtp_opus = upipe_rtp_opus_from_upipe(upipe); uint64_t timestamp = 0; size_t block_size = 0; if (!ubase_check(uref_block_size(uref, &block_size))) { upipe_warn(upipe, "fail to get uref block size"); return; } uref_rtp_get_timestamp(uref, ×tamp); uref_clock_set_pts_orig(uref, timestamp * TS_MULTIPLIER); uint64_t delta = (UINT_MAX + timestamp - (upipe_rtp_opus->last_rtp_timestamp % UINT_MAX)) % UINT_MAX; upipe_rtp_opus->last_rtp_timestamp += delta; uref_clock_set_pts_prog(uref, upipe_rtp_opus->last_rtp_timestamp * TS_MULTIPLIER); upipe_throw_clock_ref(upipe, uref, upipe_rtp_opus->last_rtp_timestamp * TS_MULTIPLIER, 0); upipe_throw_clock_ts(upipe, uref); upipe_rtp_opus_output(upipe, uref, upump_p); }
/** @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 tries to find TS packets in the buffered input urefs. * * @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_check_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_ts_check *upipe_ts_check = upipe_ts_check_from_upipe(upipe); size_t size; if (unlikely(!ubase_check(uref_block_size(uref, &size)))) { uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } while (size > upipe_ts_check->output_size) { struct uref *next = uref_block_split(uref, upipe_ts_check->output_size); if (unlikely(next == NULL)) { uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } if (!upipe_ts_check_check(upipe, uref, upump_p)) { uref_free(next); return; } size -= upipe_ts_check->output_size; uref = next; } if (size == upipe_ts_check->output_size) upipe_ts_check_check(upipe, uref, upump_p); }
/** @internal @This checks and parses a "#EXT-X-STREAM-INF" tag. * * @param upipe description structure of the pipe * @param flow_def the current flow definition * @param line the trailing characters of the line * @return an error code */ static int upipe_m3u_reader_ext_x_stream_inf(struct upipe *upipe, struct uref *flow_def, const char *line) { if (!ubase_check(uref_flow_match_def(flow_def, M3U_FLOW_DEF)) && !ubase_check(uref_flow_match_def(flow_def, MASTER_FLOW_DEF))) return UBASE_ERR_INVALID; UBASE_RETURN(uref_flow_set_def(flow_def, MASTER_FLOW_DEF)); struct uref *item; UBASE_RETURN(upipe_m3u_reader_get_item(upipe, flow_def, &item)); const char *iterator = line; struct ustring name, value; while (ubase_check(attribute_iterate(&iterator, &name, &value)) && iterator != NULL) { char value_str[value.len + 1]; int err = ustring_cpy(value, value_str, sizeof (value_str)); if (unlikely(!ubase_check(err))) { upipe_err_va(upipe, "fail to copy ustring %.*s", (int)value.len, value.at); continue; } if (!ustring_cmp_str(name, "BANDWIDTH")) { char *endptr; uint64_t bandwidth = strtoull(value_str, &endptr, 10); if (endptr == value_str) return UBASE_ERR_INVALID; err = uref_m3u_master_set_bandwidth(item, bandwidth); if (unlikely(!ubase_check(err))) upipe_err_va(upipe, "fail to set bandwidth to %s", value_str); } else if (!ustring_cmp_str(name, "CODECS")) { err = uref_m3u_master_set_codecs(item, value_str); if (unlikely(!ubase_check(err))) upipe_err_va(upipe, "fail to set codecs to %s", value_str); } else if (!ustring_cmp_str(name, "AUDIO")) { err = uref_m3u_master_set_audio(item, value_str); if (unlikely(!ubase_check(err))) upipe_err_va(upipe, "fail to set audio to %s", value_str); } else if (!ustring_cmp_str(name, "RESOLUTION")) { err = uref_m3u_master_set_resolution(item, value_str); if (unlikely(!ubase_check(err))) upipe_err_va(upipe, "fail to set resolution to %s", value_str); } else { upipe_warn_va(upipe, "ignoring attribute %.*s (%.*s)", (int)name.len, name.at, (int)value.len, value.at); } } 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_fdec_set_flow_def(struct upipe *upipe, struct uref *flow_def) { struct upipe_fdec_mgr *fdec_mgr = upipe_fdec_mgr_from_upipe_mgr(upipe->mgr); struct upipe_fdec *upipe_fdec = upipe_fdec_from_upipe(upipe); if (flow_def == NULL) return UBASE_ERR_INVALID; if (upipe_fdec->last_inner != NULL) { if (ubase_check(upipe_set_flow_def(upipe_fdec->last_inner, flow_def))) return UBASE_ERR_NONE; } upipe_fdec_store_bin_input(upipe, NULL); upipe_fdec_store_bin_output(upipe, NULL); struct upipe *avcdec = upipe_void_alloc(fdec_mgr->avcdec_mgr, uprobe_pfx_alloc( uprobe_use(&upipe_fdec->last_inner_probe), UPROBE_LOG_VERBOSE, "avcdec")); if (unlikely(avcdec == NULL)) { upipe_err_va(upipe, "couldn't allocate avcdec"); return UBASE_ERR_UNHANDLED; } if (unlikely(!ubase_check(upipe_set_flow_def(avcdec, flow_def)))) { upipe_err_va(upipe, "couldn't set avcdec flow def"); upipe_release(avcdec); return UBASE_ERR_UNHANDLED; } if (upipe_fdec->options != NULL && upipe_fdec->options->udict != NULL) { const char *key = NULL; enum udict_type type = UDICT_TYPE_END; while (ubase_check(udict_iterate(upipe_fdec->options->udict, &key, &type)) && type != UDICT_TYPE_END) { const char *value; if (key == NULL || !ubase_check(udict_get_string(upipe_fdec->options->udict, &value, type, key))) continue; if (!ubase_check(upipe_set_option(avcdec, key, value))) upipe_warn_va(upipe, "option %s=%s invalid", key, value); } } upipe_fdec_store_bin_input(upipe, upipe_use(avcdec)); upipe_fdec_store_bin_output(upipe, avcdec); return UBASE_ERR_NONE; }
/** @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_dejitter_sub_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { uint64_t date; if (ubase_check(uref_clock_get_dts_prog(uref, &date))) upipe_throw_clock_ts(upipe, uref); upipe_dejitter_output(upipe, uref, upump_p); }
/** @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; }
/** @internal @This checks if a burst is complete. * * @param upipe description structure of the pipe * @param true if the burst is complete */ static bool upipe_s337d_check_frame(struct upipe *upipe) { struct upipe_s337d *upipe_s337d = upipe_s337d_from_upipe(upipe); size_t size; if (!ubase_check(uref_block_size(upipe_s337d->next_uref, &size))) { upipe_s337d->next_frame_discard = true; return true; } return size >= upipe_s337d->next_frame_size + S337_PREAMBLE_SIZE; }
/** @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 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_block_to_sound_set_flow_def(struct upipe *upipe, struct uref *flow_def) { struct upipe_block_to_sound *upipe_block_to_sound = upipe_block_to_sound_from_upipe(upipe); if (flow_def == NULL) return UBASE_ERR_INVALID; if (unlikely(!ubase_check(uref_flow_match_def(flow_def, "block.")))) { uref_free(flow_def); return UBASE_ERR_INVALID; } flow_def = uref_dup(upipe_block_to_sound->flow_def_config); if (unlikely(flow_def == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } if(unlikely(!ubase_check(uref_flow_match_def(flow_def, "sound.s32.")))) { uref_free(flow_def); return UBASE_ERR_INVALID; } uint8_t channels, planes, sample_size; if(unlikely(!ubase_check(uref_sound_flow_get_channels(flow_def, &channels))) || unlikely(!ubase_check(uref_sound_flow_get_planes(flow_def, &planes))) || unlikely(!ubase_check(uref_sound_flow_get_sample_size(flow_def, &sample_size)))) { uref_free(flow_def); 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; } upipe_block_to_sound_store_flow_def(upipe, flow_def_dup); upipe_block_to_sound_require_ubuf_mgr(upipe, flow_def); return UBASE_ERR_NONE; }
/** helper phony pipe */ static void test_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct x264_test *x264_test = x264_test_from_upipe(upipe); uint64_t pts = 0, dts = 0; if (uref->udict != NULL) { udict_dump(uref->udict, upipe->uprobe); } if (!ubase_check(uref_clock_get_pts_prog(uref, &pts))) { upipe_warn(upipe, "received packet with no pts"); } if (!ubase_check(uref_clock_get_dts_prog(uref, &dts))) { upipe_warn(upipe, "received packet with no dts"); } upipe_dbg_va(upipe, "received pic %d, pts: %"PRIu64" , dts: %"PRIu64, x264_test->counter, pts, dts); x264_test->counter++; uref_free(uref); }
/** @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); }