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 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 reference picture. * * @param upipe description structure of the pipe * @param uref picture buffer * @return an error code */ static int upipe_vblk_set_pic_real(struct upipe *upipe, struct uref *uref) { struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe); if (upipe_vblk->ubuf) ubuf_free(upipe_vblk->ubuf); upipe_vblk->ubuf = uref->ubuf; uref->ubuf = NULL; uref_free(uref); return UBASE_ERR_NONE; }
ZEND_METHOD (Msghdr, __destruct) { int rc; zval **hdr = 0; char *ptr; if (zend_hash_find (Z_OBJPROP_P (getThis ()), "__ptr", sizeof("__ptr"), (void **) &hdr) == FAILURE) return; if ((ptr = Z_STRVAL_PP (hdr)) && (ptr = * (char **) ptr)) { ubuf_free (ptr); } }
/** @internal @This frees an audio blank pipe. * * @param upipe description structure of the pipe */ static void upipe_ablk_free(struct upipe *upipe) { struct upipe_ablk *upipe_ablk = upipe_ablk_from_upipe(upipe); upipe_throw_dead(upipe); if (upipe_ablk->ubuf) ubuf_free(upipe_ablk->ubuf); upipe_ablk_clean_flow_def(upipe); upipe_ablk_clean_ubuf_mgr(upipe); upipe_ablk_clean_output(upipe); upipe_ablk_clean_urefcount(upipe); upipe_ablk_free_flow(upipe); }
/** @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; } }
static VALUE rb_sp_send (VALUE self, VALUE eid, VALUE msg) { int _eid = FIX2INT (eid); int rc; VALUE rb_hdr = 0; char *hdr = 0; char *ubuf = ubuf_alloc (RSTRING (msg)->len); memcpy (ubuf, RSTRING (msg)->ptr, ubuf_len (ubuf)); /* How can i checking the valid rb_values, f*****g the ruby extension here */ if ((rb_hdr = rb_iv_get (msg, "@hdr")) != 4) { Data_Get_Struct (rb_hdr, char, hdr); if (hdr) ubufctl (hdr, SCOPY, ubuf); } if ((rc = sp_send (_eid, ubuf))) ubuf_free (ubuf); return INT2FIX (rc); }
/** @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); }
static void xclient (const char *pf) { int sfd, i; int64_t nbytes; char buf[1024] = {}; char *ubuf; char host[1024] = {}; sprintf (host, "%s%s", pf, "://127.0.0.1:18897"); randstr (buf, 1024); BUG_ON ( (sfd = xconnect (host) ) < 0); for (i = 0; i < cnt; i++) { nbytes = rand() % 1024; ubuf = ubuf_alloc (nbytes); memcpy (ubuf, buf, nbytes); BUG_ON (0 != xsend (sfd, ubuf) ); BUG_ON (0 != xrecv (sfd, &ubuf) ); DEBUG_OFF ("%d recv response", sfd); assert (memcmp (ubuf, buf, nbytes) == 0); ubuf_free (ubuf); } xclose (sfd); }
/** @internal @This sets the input flow def. * * @param upipe description structure of the pipe * @param flow_def the flow format to set * @return an error code */ static int upipe_vblk_set_flow_def(struct upipe *upipe, struct uref *flow_def) { struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe); if (!ubase_check(uref_flow_match_def(flow_def, UREF_VOID_FLOW_DEF)) && !ubase_check(upipe_vblk_check_flow_def(upipe, flow_def))) return UBASE_ERR_INVALID; struct uref *input_flow_def = uref_dup(flow_def); if (unlikely(!input_flow_def)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } upipe_vblk_store_flow_def_input(upipe, input_flow_def); if (ubase_check(uref_flow_match_def(flow_def, UREF_VOID_FLOW_DEF))) return UBASE_ERR_NONE; uint64_t hsize = 0, vsize = 0; UBASE_RETURN(uref_pic_flow_get_hsize(flow_def, &hsize)); UBASE_RETURN(uref_pic_flow_get_vsize(flow_def, &vsize)); struct uref *flow_def_dup = uref_dup(flow_def); if (unlikely(!flow_def_dup)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } struct urational sar; uref_pic_flow_clear_format(flow_def_dup); uref_pic_flow_copy_format(flow_def_dup, flow_def); uref_pic_flow_set_hsize(flow_def_dup, hsize); uref_pic_flow_set_vsize(flow_def_dup, vsize); if (likely(ubase_check(uref_pic_flow_get_sar(flow_def, &sar)))) { uref_pic_flow_set_sar(flow_def_dup, sar); } else { uref_pic_flow_delete_sar(flow_def_dup); } bool overscan; if (likely(ubase_check(uref_pic_flow_get_overscan(flow_def, &overscan)))) { uref_pic_flow_set_overscan(flow_def_dup, overscan); } else { uref_pic_flow_delete_overscan(flow_def_dup); } if (likely(ubase_check(uref_pic_get_progressive(flow_def)))) { uref_pic_set_progressive(flow_def_dup); } else { uref_pic_delete_progressive(flow_def_dup); } upipe_vblk_store_flow_def(upipe, flow_def_dup); if (upipe_vblk->ubuf) { ubuf_free(upipe_vblk->ubuf); upipe_vblk->ubuf = NULL; } if (upipe_vblk->ubuf_mgr && !ubase_check(ubuf_mgr_check(upipe_vblk->ubuf_mgr, flow_def_dup))) { ubuf_mgr_release(upipe_vblk->ubuf_mgr); upipe_vblk->ubuf_mgr = NULL; } return UBASE_ERR_NONE; }
static void upipe_rtp_h264_output_nalu(struct upipe *upipe, uint8_t nalu, struct uref *uref, struct upump **upump_p) { size_t size = 0; if (unlikely(!ubase_check(uref_block_size(uref, &size)))) { upipe_err(upipe, "fail to get block size"); return; } bool split = size > RTP_SPLIT_SIZE; uint32_t fragment = 0; while (size) { bool last_fragment = size <= RTP_SPLIT_SIZE; size_t split_size = last_fragment ? size : RTP_SPLIT_SIZE; uint8_t hdr[2] = { nalu, 0 }; size_t hdr_size = 1; if (split) { if (!fragment) hdr[1] = FU_START; else if (last_fragment) hdr[1] = FU_END; hdr[1] |= NALU_TYPE(hdr[0]); hdr[0] = NALU_F(hdr[0]) | NALU_NRI(hdr[0]) | FU_A; hdr_size++; } struct uref *next = NULL; if (!last_fragment) { next = uref_block_split(uref, split_size); if (unlikely(next == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } } /* FIXME should require a ubuf_mgr */ struct ubuf *header = ubuf_block_alloc(uref->ubuf->mgr, hdr_size * sizeof (hdr[0])); if (unlikely(header == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); uref_free(uref); uref_free(next); return; } uint8_t *buf = NULL; int buf_size = hdr_size; ubuf_block_write(header, 0, &buf_size, &buf); memcpy(buf, hdr, hdr_size * sizeof (hdr[0])); ubuf_block_unmap(header, 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); uref_free(uref); uref_free(next); return; } uref_attach_ubuf(uref, header); uref_clock_set_cr_dts_delay(uref, 0); upipe_rtp_h264_output(upipe, uref, upump_p); size -= split_size; fragment++; uref = next; } }
/** @internal @This handles data from sound allocator. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static void upipe_tblk_handle_sound(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_tblk *upipe_tblk = upipe_tblk_from_upipe(upipe); /* Always operate on the first channel plane. */ const char *channel = NULL; if (unlikely(uref->ubuf == NULL || !ubase_check(ubuf_sound_plane_iterate(uref->ubuf, &channel)) || channel == NULL)) { uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_INVALID); return; } /* First try the ubuf_mem_shared method. */ struct ubuf *ubuf = ubuf_block_mem_alloc_from_sound(upipe_tblk->ubuf_mgr, uref->ubuf, channel); if (unlikely(ubuf == NULL)) { /* We have to memcpy the thing. */ size_t samples; uint8_t sample_size; if (unlikely(!ubase_check(uref_sound_size(uref, &samples, &sample_size)))) { uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_INVALID); return; } size_t size = samples * sample_size; ubuf = ubuf_block_alloc(upipe_tblk->ubuf_mgr, size); if (unlikely(ubuf == NULL)) { uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_ALLOC); return; } const uint8_t *r; if (unlikely(!ubase_check(uref_sound_plane_read_uint8_t(uref, channel, 0, -1, &r)))) { ubuf_free(ubuf); uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_ALLOC); return; } uint8_t *w; int end = -1; if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &end, &w)))) { uref_sound_plane_unmap(uref, channel, 0, -1); ubuf_free(ubuf); uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_ALLOC); return; } memcpy(w, r, size); ubuf_block_unmap(ubuf, 0); uref_sound_plane_unmap(uref, channel, 0, -1); } uref_attach_ubuf(uref, ubuf); upipe_tblk_output(upipe, uref, upump_p); }
/** @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; }
/** @internal @This converts block urefs to sound 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_block_to_sound_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_block_to_sound *upipe_block_to_sound = upipe_block_to_sound_from_upipe(upipe); /* get block size */ size_t block_size = 0; uref_block_size(uref, &block_size); /* drop incomplete samples */ if ((block_size % upipe_block_to_sound->sample_size) != 0) { upipe_warn(upipe, "Incomplete samples detected"); } int samples = block_size / upipe_block_to_sound->sample_size; block_size = samples * upipe_block_to_sound->sample_size; /* alloc sound ubuf */ struct ubuf *ubuf_block_to_sound = ubuf_sound_alloc(upipe_block_to_sound->ubuf_mgr, samples); if (unlikely(ubuf_block_to_sound == NULL)) { uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } /* map sound ubuf for writing */ int32_t *w; if (unlikely(!ubase_check(ubuf_sound_write_int32_t(ubuf_block_to_sound, 0, -1, &w, upipe_block_to_sound->planes)))) { upipe_err(upipe, "could not write uref, dropping samples"); ubuf_sound_unmap(ubuf_block_to_sound, 0, -1, upipe_block_to_sound->planes); ubuf_free(ubuf_block_to_sound); uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } /* map block ubuf for reading */ const uint8_t *r; int end = -1; if (unlikely(!ubase_check(uref_block_read(uref, 0, &end, &r)))) { upipe_err(upipe, "could not read uref, dropping samples"); ubuf_sound_unmap(ubuf_block_to_sound, 0, -1, upipe_block_to_sound->planes); ubuf_block_unmap(uref->ubuf, 0); ubuf_free(ubuf_block_to_sound); uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } /* copy block to sound */ memcpy(w, r, block_size); /* unmap ubufs */ ubuf_sound_unmap(ubuf_block_to_sound, 0, -1, upipe_block_to_sound->planes); ubuf_block_unmap(uref->ubuf, 0); /* attach sound ubuf to uref */ uref_attach_ubuf(uref, ubuf_block_to_sound); /* output pipe */ upipe_block_to_sound_output(upipe, uref, upump_p); }
/** @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; }
int main(int argc, char **argv) { struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); assert(umem_mgr != NULL); struct ubuf_mgr *mgr; struct ubuf *ubuf1, *ubuf2; const char *channel; size_t size; uint8_t sample_size; uint8_t *w; const uint8_t *r; /* packed s16 stereo */ mgr = ubuf_sound_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr, 4, 32); assert(mgr != NULL); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "lr")); ubuf1 = ubuf_sound_alloc(mgr, 32); assert(ubuf1 != NULL); ubase_assert(ubuf_sound_size(ubuf1, &size, &sample_size)); assert(size == 32); assert(sample_size == 4); channel = NULL; unsigned int nb_planes = 0; while (ubase_check(ubuf_sound_plane_iterate(ubuf1, &channel)) && channel != NULL) { nb_planes++; assert(!strcmp(channel, "lr")); } assert(nb_planes == 1); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "lr", 0, -1, &r)); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "lr", 0, -1)); fill_in(ubuf1); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "lr", 2, 1, &r)); assert(*r == 'l' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "lr", 2, 1)); ubuf2 = ubuf_dup(ubuf1); assert(ubuf2 != NULL); ubase_nassert(ubuf_sound_plane_write_uint8_t(ubuf1, "lr", 0, -1, &w)); ubuf_free(ubuf2); ubase_nassert(ubuf_sound_resize(ubuf1, 0, 33)); ubase_assert(ubuf_sound_resize(ubuf1, 2, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "lr", 0, -1, &r)); assert(r[0] == 'l' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "lr", 0, -1)); ubase_assert(ubuf_sound_resize(ubuf1, 0, 29)); ubuf_free(ubuf1); ubuf_mgr_release(mgr); /* planar float 5.1 */ mgr = ubuf_sound_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr, sizeof(float), 32); assert(mgr != NULL); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "l")); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "r")); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "c")); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "L")); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "R")); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "S")); ubuf1 = ubuf_sound_alloc(mgr, 32); assert(ubuf1 != NULL); ubase_assert(ubuf_sound_size(ubuf1, &size, &sample_size)); assert(size == 32); assert(sample_size == sizeof(float)); channel = NULL; nb_planes = 0; while (ubase_check(ubuf_sound_plane_iterate(ubuf1, &channel)) && channel != NULL) nb_planes++; assert(nb_planes == 6); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "l", 0, -1, &r)); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "l", 0, -1)); fill_in(ubuf1); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "l", 2, 1, &r)); assert(*r == 'l' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "l", 2, 1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "r", 2, 1, &r)); assert(*r == 'r' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "r", 2, 1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "c", 2, 1, &r)); assert(*r == 'c' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "c", 2, 1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "L", 2, 1, &r)); assert(*r == 'L' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "L", 2, 1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "R", 2, 1, &r)); assert(*r == 'R' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "R", 2, 1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "S", 2, 1, &r)); assert(*r == 'S' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "S", 2, 1)); ubuf2 = ubuf_dup(ubuf1); assert(ubuf2 != NULL); ubase_nassert(ubuf_sound_plane_write_uint8_t(ubuf1, "l", 0, -1, &w)); ubuf_free(ubuf2); ubase_nassert(ubuf_sound_resize(ubuf1, 0, 33)); ubase_assert(ubuf_sound_resize(ubuf1, 2, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "l", 0, -1, &r)); assert(r[0] == 'l' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "l", 0, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "r", 0, -1, &r)); assert(r[0] == 'r' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "r", 0, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "c", 0, -1, &r)); assert(r[0] == 'c' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "c", 0, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "L", 0, -1, &r)); assert(r[0] == 'L' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "L", 0, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "R", 0, -1, &r)); assert(r[0] == 'R' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "R", 0, -1)); ubase_assert(ubuf_sound_plane_read_uint8_t(ubuf1, "S", 0, -1, &r)); assert(r[0] == 'S' + 8); ubase_assert(ubuf_sound_plane_unmap(ubuf1, "S", 0, -1)); ubase_assert(ubuf_sound_resize(ubuf1, 0, 29)); ubuf_free(ubuf1); ubuf_mgr_release(mgr); /* sound -> block transformation */ mgr = ubuf_sound_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr, 4, 32); assert(mgr != NULL); ubase_assert(ubuf_sound_mem_mgr_add_plane(mgr, "lr")); ubuf1 = ubuf_sound_alloc(mgr, 32); assert(ubuf1 != NULL); fill_in(ubuf1); struct ubuf_mgr *block_mgr = ubuf_block_mem_mgr_alloc(UBUF_POOL_DEPTH, UBUF_POOL_DEPTH, umem_mgr, 0, 0, 0, 0); struct ubuf *ubuf_block = ubuf_block_mem_alloc_from_sound(block_mgr, ubuf1, "lr"); assert(ubuf_block != NULL); ubase_assert(ubuf_block_size(ubuf_block, &size)); assert(size == 32 * 4); int size2 = -1; ubase_assert(ubuf_block_read(ubuf_block, 0, &size2, &r)); assert(size2 == 32 * 4); assert(r[0] == 'l'); ubuf_free(ubuf_block); ubuf_mgr_release(block_mgr); ubuf_free(ubuf1); ubuf_mgr_release(mgr); umem_mgr_release(umem_mgr); return 0; }
/** @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 * @return false if the input must be blocked */ static bool upipe_speexdsp_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); struct urational drift_rate; if (!ubase_check(uref_clock_get_rate(uref, &drift_rate))) drift_rate = (struct urational){ 1, 1 }; /* reinitialize resampler when drift rate changes */ if (urational_cmp(&drift_rate, &upipe_speexdsp->drift_rate)) { upipe_speexdsp->drift_rate = drift_rate; spx_uint32_t ratio_num = drift_rate.den; spx_uint32_t ratio_den = drift_rate.num; spx_uint32_t in_rate = upipe_speexdsp->rate * ratio_num / ratio_den; spx_uint32_t out_rate = upipe_speexdsp->rate; int err = speex_resampler_set_rate_frac(upipe_speexdsp->ctx, ratio_num, ratio_den, in_rate, out_rate); if (err) { upipe_err_va(upipe, "Couldn't resample from %u to %u: %s", in_rate, out_rate, speex_resampler_strerror(err)); } else { upipe_dbg_va(upipe, "Resampling from %u to %u", in_rate, out_rate); } } size_t size; if (!ubase_check(uref_sound_size(uref, &size, NULL /* sample_size */))) { uref_free(uref); return true; } struct ubuf *ubuf = ubuf_sound_alloc(upipe_speexdsp->ubuf_mgr, size + 10); if (!ubuf) return false; const void *in; uref_sound_read_void(uref, 0, -1, &in, 1); void *out; ubuf_sound_write_void(ubuf, 0, -1, &out, 1); spx_uint32_t in_len = size; /* input size */ spx_uint32_t out_len = size + 10; /* available output size */ int err; if (upipe_speexdsp->f32) err = speex_resampler_process_interleaved_float(upipe_speexdsp->ctx, in, &in_len, out, &out_len); else err = speex_resampler_process_interleaved_int(upipe_speexdsp->ctx, in, &in_len, out, &out_len); if (err) { upipe_err_va(upipe, "Could not resample: %s", speex_resampler_strerror(err)); } uref_sound_unmap(uref, 0, -1, 1); ubuf_sound_unmap(ubuf, 0, -1, 1); if (err) { ubuf_free(ubuf); } else { ubuf_sound_resize(ubuf, 0, out_len); uref_attach_ubuf(uref, ubuf); } upipe_speexdsp_output(upipe, uref, upump_p); return true; } /** @internal @This receives incoming uref. * * @param upipe description structure of the pipe * @param uref uref structure describing the picture * @param upump_p reference to pump that generated the buffer */ static void upipe_speexdsp_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { if (!upipe_speexdsp_check_input(upipe)) { upipe_speexdsp_hold_input(upipe, uref); upipe_speexdsp_block_input(upipe, upump_p); } else if (!upipe_speexdsp_handle(upipe, uref, upump_p)) { upipe_speexdsp_hold_input(upipe, uref); upipe_speexdsp_block_input(upipe, upump_p); /* Increment upipe refcount to avoid disappearing before all packets * have been sent. */ upipe_use(upipe); } } /** @internal @This receives a provided ubuf manager. * * @param upipe description structure of the pipe * @param flow_format amended flow format * @return an error code */ static int upipe_speexdsp_check(struct upipe *upipe, struct uref *flow_format) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); if (flow_format != NULL) upipe_speexdsp_store_flow_def(upipe, flow_format); if (upipe_speexdsp->flow_def == NULL) return UBASE_ERR_NONE; bool was_buffered = !upipe_speexdsp_check_input(upipe); upipe_speexdsp_output_input(upipe); upipe_speexdsp_unblock_input(upipe); if (was_buffered && upipe_speexdsp_check_input(upipe)) { /* All packets have been output, release again the pipe that has been * used in @ref upipe_speexdsp_input. */ upipe_release(upipe); } 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_speexdsp_set_flow_def(struct upipe *upipe, struct uref *flow_def) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); if (flow_def == NULL) return UBASE_ERR_INVALID; const char *def; UBASE_RETURN(uref_flow_get_def(flow_def, &def)) if (unlikely(ubase_ncmp(def, "sound.f32.") && ubase_ncmp(def, "sound.s16."))) return UBASE_ERR_INVALID; uint8_t in_planes; if (unlikely(!ubase_check(uref_sound_flow_get_planes(flow_def, &in_planes)))) return UBASE_ERR_INVALID; if (in_planes != 1) { upipe_err(upipe, "only interleaved audio is supported"); return UBASE_ERR_INVALID; } if (!ubase_check(uref_sound_flow_get_rate(flow_def, &upipe_speexdsp->rate))) { upipe_err(upipe, "no sound rate defined"); uref_dump(flow_def, upipe->uprobe); return UBASE_ERR_INVALID; } uint8_t channels; if (unlikely(!ubase_check(uref_sound_flow_get_channels(flow_def, &channels)))) return UBASE_ERR_INVALID; flow_def = uref_dup(flow_def); if (unlikely(flow_def == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } upipe_speexdsp_require_ubuf_mgr(upipe, flow_def); if (upipe_speexdsp->ctx) speex_resampler_destroy(upipe_speexdsp->ctx); upipe_speexdsp->f32 = !ubase_ncmp(def, "sound.f32."); int err; upipe_speexdsp->ctx = speex_resampler_init(channels, upipe_speexdsp->rate, upipe_speexdsp->rate, upipe_speexdsp->quality, &err); if (!upipe_speexdsp->ctx) { upipe_err_va(upipe, "Could not create resampler: %s", speex_resampler_strerror(err)); return UBASE_ERR_INVALID; } return UBASE_ERR_NONE; } /** @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_speexdsp_provide_flow_format(struct upipe *upipe, struct urequest *request) { const char *def; UBASE_RETURN(uref_flow_get_def(request->uref, &def)) uint8_t channels; UBASE_RETURN(uref_sound_flow_get_channels(request->uref, &channels)) uint8_t planes; UBASE_RETURN(uref_sound_flow_get_planes(request->uref, &planes)) uint8_t sample_size; UBASE_RETURN(uref_sound_flow_get_sample_size(request->uref, &sample_size)) struct uref *flow = uref_dup(request->uref); UBASE_ALLOC_RETURN(flow); uref_sound_flow_clear_format(flow); uref_sound_flow_set_planes(flow, 0); uref_sound_flow_set_channels(flow, channels); uref_sound_flow_add_plane(flow, "all"); if (ubase_ncmp(def, "sound.s16.")) { uref_flow_set_def(flow, "sound.f32."); /* prefer f32 over s16 */ uref_sound_flow_set_sample_size(flow, 4 * channels); } else { uref_flow_set_def(flow, def); uref_sound_flow_set_sample_size(flow, (planes > 1) ? sample_size : sample_size / channels); } return urequest_provide_flow_format(request, flow); } /** @internal @This processes control commands on a speexdsp pipe. * * @param upipe description structure of the pipe * @param command type of command to process * @param args arguments of the command * @return an error code */ static int upipe_speexdsp_control(struct upipe *upipe, int command, va_list args) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); switch (command) { /* generic commands */ case UPIPE_REGISTER_REQUEST: { struct urequest *request = va_arg(args, struct urequest *); if (request->type == UREQUEST_FLOW_FORMAT) return upipe_speexdsp_provide_flow_format(upipe, request); if (request->type == UREQUEST_UBUF_MGR) return upipe_throw_provide_request(upipe, request); return upipe_speexdsp_alloc_output_proxy(upipe, request); } case UPIPE_UNREGISTER_REQUEST: { struct urequest *request = va_arg(args, struct urequest *); if (request->type == UREQUEST_FLOW_FORMAT || request->type == UREQUEST_UBUF_MGR) return UBASE_ERR_NONE; return upipe_speexdsp_free_output_proxy(upipe, request); } case UPIPE_GET_OUTPUT: { struct upipe **p = va_arg(args, struct upipe **); return upipe_speexdsp_get_output(upipe, p); } case UPIPE_SET_OUTPUT: { struct upipe *output = va_arg(args, struct upipe *); return upipe_speexdsp_set_output(upipe, output); } case UPIPE_GET_FLOW_DEF: { struct uref **p = va_arg(args, struct uref **); return upipe_speexdsp_get_flow_def(upipe, p); } case UPIPE_SET_FLOW_DEF: { struct uref *flow = va_arg(args, struct uref *); return upipe_speexdsp_set_flow_def(upipe, flow); } case UPIPE_SET_OPTION: { const char *option = va_arg(args, const char *); const char *value = va_arg(args, const char *); if (strcmp(option, "quality")) return UBASE_ERR_INVALID; if (upipe_speexdsp->ctx) return UBASE_ERR_BUSY; int quality = atoi(value); if (quality > SPEEX_RESAMPLER_QUALITY_MAX) { quality = SPEEX_RESAMPLER_QUALITY_MAX; upipe_err_va(upipe, "Clamping quality to %d", SPEEX_RESAMPLER_QUALITY_MAX); } else if (quality < SPEEX_RESAMPLER_QUALITY_MIN) { quality = SPEEX_RESAMPLER_QUALITY_MIN; upipe_err_va(upipe, "Clamping quality to %d", SPEEX_RESAMPLER_QUALITY_MIN); } upipe_speexdsp->quality = quality; return UBASE_ERR_NONE; } default: return UBASE_ERR_UNHANDLED; } } /** @internal @This allocates a speexdsp pipe. * * @param mgr common management structure * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to upipe or NULL in case of allocation error */ static struct upipe *upipe_speexdsp_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { struct upipe *upipe = upipe_speexdsp_alloc_void(mgr, uprobe, signature, args); if (unlikely(upipe == NULL)) return NULL; struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); upipe_speexdsp->ctx = NULL; upipe_speexdsp->drift_rate = (struct urational){ 0, 0 }; upipe_speexdsp->quality = SPEEX_RESAMPLER_QUALITY_MAX; upipe_speexdsp_init_urefcount(upipe); upipe_speexdsp_init_ubuf_mgr(upipe); upipe_speexdsp_init_output(upipe); upipe_speexdsp_init_flow_def(upipe); upipe_speexdsp_init_input(upipe); upipe_throw_ready(upipe); return upipe; } /** @This frees a upipe. * * @param upipe description structure of the pipe */ static void upipe_speexdsp_free(struct upipe *upipe) { struct upipe_speexdsp *upipe_speexdsp = upipe_speexdsp_from_upipe(upipe); if (likely(upipe_speexdsp->ctx)) speex_resampler_destroy(upipe_speexdsp->ctx); upipe_throw_dead(upipe); upipe_speexdsp_clean_input(upipe); upipe_speexdsp_clean_output(upipe); upipe_speexdsp_clean_flow_def(upipe); upipe_speexdsp_clean_ubuf_mgr(upipe); upipe_speexdsp_clean_urefcount(upipe); upipe_speexdsp_free_void(upipe); } /** module manager static descriptor */ static struct upipe_mgr upipe_speexdsp_mgr = { .refcount = NULL, .signature = UPIPE_SPEEXDSP_SIGNATURE, .upipe_alloc = upipe_speexdsp_alloc, .upipe_input = upipe_speexdsp_input, .upipe_control = upipe_speexdsp_control, .upipe_mgr_control = NULL }; /** @This returns the management structure for speexdsp pipes * * @return pointer to manager */ struct upipe_mgr *upipe_speexdsp_mgr_alloc(void) { return &upipe_speexdsp_mgr; }
/** @internal @This handles packets. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump upump structure */ static void upipe_avcdec_input_packet(struct upipe *upipe, struct uref *uref, struct upump *upump) { uint8_t *inbuf; size_t insize = 0; struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe); assert(upipe); assert(uref); if (upipe_avcdec->upump_av_deal) { /* pending open_codec callback */ upipe_dbg(upipe, "Received packet while open_codec pending"); if (upump) { upump_mgr_sink_block(upump->mgr); upump_mgr_use(upump->mgr); upipe_avcdec->saved_upump_mgr = upump->mgr; } if (upipe_avcdec->saved_uref) { upipe_warn(upipe, "Dropping previously saved packet !"); uref_free(upipe_avcdec->saved_uref); } upipe_avcdec->saved_uref = uref; return; } else if (upipe_avcdec->saved_uref) { upipe_dbg(upipe, "Processing previously saved packet"); struct uref *prev_uref = upipe_avcdec->saved_uref; upipe_avcdec->saved_uref = NULL; /* Not a typo, using the current upump here */ upipe_avcdec_input_packet(upipe, prev_uref, upump); } if (!upipe_avcdec->context) { uref_free(uref); upipe_warn(upipe, "Received packet but decoder is not initialized"); return; } /* avcodec input buffer needs to be at least 4-byte aligned and FF_INPUT_BUFFER_PADDING_SIZE larger than actual input size. Thus, extract ubuf content in a properly allocated buffer. Padding must be zeroed. */ uref_block_size(uref, &insize); if (unlikely(!insize)) { upipe_warn(upipe, "Received packet with size 0, dropping"); uref_free(uref); return; } upipe_dbg_va(upipe, "Received packet %u - size : %u", upipe_avcdec->counter, insize); inbuf = malloc(insize + FF_INPUT_BUFFER_PADDING_SIZE); if (unlikely(!inbuf)) { upipe_throw_aerror(upipe); return; } memset(inbuf, 0, insize + FF_INPUT_BUFFER_PADDING_SIZE); uref_block_extract(uref, 0, insize, inbuf); ubuf_free(uref_detach_ubuf(uref)); uref_pic_set_number(uref, upipe_avcdec->counter); /* Track current uref in pipe structure - required for buffer allocation * in upipe_avcdec_get_buffer */ upipe_avcdec->uref = uref; upipe_avcdec_process_buf(upipe, inbuf, insize, upump); free(inbuf); uref_free(uref); upipe_avcdec->counter++; }
/** @internal @This handles input. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to upump structure * @return always true */ static bool upipe_filter_blend_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_filter_blend *upipe_filter_blend = upipe_filter_blend_from_upipe(upipe); const char *def; if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) { upipe_filter_blend_store_flow_def(upipe, NULL); upipe_filter_blend_require_ubuf_mgr(upipe, uref); return true; } if (upipe_filter_blend->flow_def == NULL) return false; const uint8_t *in; uint8_t *out; uint8_t hsub, vsub, macropixel_size; size_t stride_in = 0, stride_out = 0, width, height; const char *chroma = NULL; struct ubuf *ubuf_deint = NULL; // Now process frames uref_pic_size(uref, &width, &height, NULL); upipe_verbose_va(upipe, "received pic (%zux%zu)", width, height); assert(upipe_filter_blend->ubuf_mgr); ubuf_deint = ubuf_pic_alloc(upipe_filter_blend->ubuf_mgr, width, height); if (unlikely(!ubuf_deint)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); goto error; } // Iterate planes while (ubase_check(uref_pic_plane_iterate(uref, &chroma)) && chroma) { // map all if (unlikely(!ubase_check(uref_pic_plane_size(uref, chroma, &stride_in, &hsub, &vsub, ¯opixel_size)))) { upipe_err_va(upipe, "Could not read origin chroma %s", chroma); goto error; } if (unlikely(!ubase_check(ubuf_pic_plane_size(ubuf_deint, chroma, &stride_out, NULL, NULL, NULL)))) { upipe_err_va(upipe, "Could not read dest chroma %s", chroma); goto error; } uref_pic_plane_read(uref, chroma, 0, 0, -1, -1, &in); ubuf_pic_plane_write(ubuf_deint, chroma, 0, 0, -1, -1, &out); // process plane upipe_filter_blend_plane(in, out, stride_in, stride_out, (size_t) height/vsub, macropixel_size); // unmap all uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1); ubuf_pic_plane_unmap(ubuf_deint, chroma, 0, 0, -1, -1); } // Attach new ubuf and output frame uref_attach_ubuf(uref, ubuf_deint); uref_pic_set_progressive(uref); uref_pic_delete_tff(uref); upipe_filter_blend_output(upipe, uref, upump_p); return true; error: uref_free(uref); if (ubuf_deint) { ubuf_free(ubuf_deint); } return true; }
/** @internal @This handles data from pic allocator. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static void upipe_tblk_handle_pic(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_tblk *upipe_tblk = upipe_tblk_from_upipe(upipe); /* Always operate on the first chroma plane. */ const char *chroma = NULL; if (unlikely(uref->ubuf == NULL || !ubase_check(ubuf_pic_plane_iterate(uref->ubuf, &chroma)) || chroma == NULL)) { uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_INVALID); return; } /* First try the ubuf_mem_shared method. */ struct ubuf *ubuf = ubuf_block_mem_alloc_from_pic(upipe_tblk->ubuf_mgr, uref->ubuf, chroma); if (unlikely(ubuf == NULL)) { /* We have to memcpy the thing. */ size_t hsize, vsize, stride; uint8_t macropixel, hsub, vsub, macropixel_size; if (unlikely(!ubase_check(uref_pic_size(uref, NULL, &vsize, NULL)) || !ubase_check(uref_pic_plane_size(uref, chroma, &stride, NULL, &vsub, NULL)))) { uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_INVALID); return; } size_t size = stride * vsize / vsub; ubuf = ubuf_block_alloc(upipe_tblk->ubuf_mgr, size); if (unlikely(ubuf == NULL)) { uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_ALLOC); return; } const uint8_t *r; if (unlikely(!ubase_check(uref_pic_plane_read(uref, chroma, 0, 0, -1, -1, &r)))) { ubuf_free(ubuf); uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_ALLOC); return; } uint8_t *w; int end = -1; if (unlikely(!ubase_check(ubuf_block_write(ubuf, 0, &end, &w)))) { uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1); ubuf_free(ubuf); uref_free(uref); upipe_throw_error(upipe, UBASE_ERR_ALLOC); return; } memcpy(w, r, size); ubuf_block_unmap(ubuf, 0); uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1); } uref_attach_ubuf(uref, ubuf); upipe_tblk_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 bool upipe_s337_encaps_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_s337_encaps *upipe_s337_encaps = upipe_s337_encaps_from_upipe(upipe); if (!upipe_s337_encaps->ubuf_mgr) return false; size_t block_size; if (!ubase_check(uref_block_size(uref, &block_size))) { upipe_err(upipe, "Couldn't read block size"); uref_free(uref); return true; } struct ubuf *ubuf = ubuf_sound_alloc(upipe_s337_encaps->ubuf_mgr, A52_FRAME_SAMPLES); if (!ubuf) return false; if (block_size / 2 > A52_FRAME_SAMPLES - 4) { upipe_err_va(upipe, "AC-3 block size %zu too big", block_size); block_size = (A52_FRAME_SAMPLES - 4) * 2; } int32_t *out_data; ubuf_sound_write_int32_t(ubuf, 0, -1, &out_data, 1); /* Pa, Pb, Pc, Pd */ out_data[0] = (S337_PREAMBLE_A1 << 24) | (S337_PREAMBLE_A2 << 16); out_data[1] = (S337_PREAMBLE_B1 << 24) | (S337_PREAMBLE_B2 << 16); out_data[2] = (S337_TYPE_A52 << 16) | (S337_MODE_16 << 21) | (S337_TYPE_A52_REP_RATE_FLAG << 24); out_data[3] = ((block_size * 8) & 0xffff) << 16; int offset = 0; uint8_t tmp = 0; while (block_size) { const uint8_t *buf; int size = block_size; if (!ubase_check(uref_block_read(uref, offset, &size, &buf)) || size == 0) { ubuf_sound_unmap(ubuf, 0, -1, 1); ubuf_free(ubuf); uref_free(uref); return true; } if (offset & 1) { out_data[4 + offset/2] = (tmp << 24) | (buf[0] << 16); buf++; offset++; block_size--; size--; } for (int i = 0; i < size/2; i++) out_data[4 + offset/2 + i] = (buf[2*i + 0] << 24) | (buf[2*i + 1] << 16); if (size & 1) tmp = buf[size-1]; uref_block_unmap(uref, offset); block_size -= size; offset += size; } memset(&out_data[4 + offset/2], 0, 4 * (A52_FRAME_SAMPLES*2 - 4 - offset/2)); ubuf_sound_unmap(ubuf, 0, -1, 1); uref_attach_ubuf(uref, ubuf); upipe_s337_encaps_output(upipe, uref, upump_p); return true; }