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 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 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 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; }