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 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 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 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 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); }
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; }
/** @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 checks and parses a line of a m3u file. * * @param upipe description structure of the pipe * @param flow_def the current flow definition * @param uref pointer to uref carrying the line to parse * @return an error code */ static int upipe_m3u_reader_process_line(struct upipe *upipe, struct uref *flow_def, struct uref *uref) { static const struct { const char *pfx; int (*cb)(struct upipe *, struct uref *, const char *); } ext_cb[] = { { "#EXTM3U", upipe_m3u_reader_process_m3u }, { "#EXT-X-VERSION:", upipe_m3u_reader_process_version }, { "#EXT-X-TARGETDURATION:", upipe_m3u_reader_process_target_duration }, { "#EXT-X-PLAYLIST-TYPE:", upipe_m3u_reader_process_playlist_type }, { "#EXTINF:", upipe_m3u_reader_process_extinf }, { "#EXT-X-BYTERANGE:", upipe_m3u_reader_process_byte_range }, { "#EXT-X-MEDIA:", upipe_m3u_reader_process_media }, { "#EXT-X-STREAM-INF:", upipe_m3u_reader_ext_x_stream_inf }, { "#EXT-X-MEDIA-SEQUENCE:", upipe_m3u_reader_ext_x_media_sequence }, { "#EXT-X-ENDLIST", upipe_m3u_reader_ext_x_endlist }, { "#EXT-X-KEY:", upipe_m3u_reader_key }, }; size_t block_size; UBASE_RETURN(uref_block_size(uref, &block_size)); uint8_t buffer[block_size + 1]; memset(buffer, 0, sizeof (buffer)); UBASE_RETURN(uref_block_extract(uref, 0, block_size, buffer)); char *line = (char *)buffer; /* remove end of line */ if (strlen(line) && line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; if (strlen(line) && line[strlen(line) - 1] == '\r') line[strlen(line) - 1] = '\0'; } if (!strlen(line)) return UBASE_ERR_NONE; if (*line == '#') { for (unsigned i = 0; i < UBASE_ARRAY_SIZE(ext_cb); i++) { if (strncmp(line, ext_cb[i].pfx, strlen(ext_cb[i].pfx))) continue; return ext_cb[i].cb(upipe, flow_def, line + strlen(ext_cb[i].pfx)); } upipe_dbg_va(upipe, "ignore `%s'", line); return UBASE_ERR_NONE; } return upipe_m3u_reader_process_uri(upipe, flow_def, line); }
/** @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 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 void upipe_dump_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_dump *upipe_dump = upipe_dump_from_upipe(upipe); uref_dump(uref, upipe->uprobe); size_t total_size; ubase_assert(uref_block_size(uref, &total_size)); upipe_notice_va(upipe, "dumping ubuf %p of size %zu", uref->ubuf, total_size); if (upipe_dump->max_len != (size_t)-1 && total_size > upipe_dump->max_len) total_size = upipe_dump->max_len; unsigned int count = 0; uint8_t line[16]; int offset = 0; while (total_size) { const uint8_t *buf; int size = total_size; ubase_assert(uref_block_read(uref, offset, &size, &buf)); assert(size != 0); total_size -= size; for (unsigned i = 0; i < size; i++, count++) { line[count % 16] = buf[i]; if (!((count + 1) % 16) || (!total_size && (i + 1 == size))) upipe_dump_line(upipe, count - (count % 16), line, (count % 16) + 1); } ubase_assert(uref_block_unmap(uref, offset)); offset += size; } #define UPIPE_DUMP_SEP \ "--------------------------------------------" \ "-------------------------------------------" upipe_notice(upipe, UPIPE_DUMP_SEP); upipe_dump_output(upipe, uref, upump_p); }
/** @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 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; } bool first = true; while (size > upipe_ts_check->output_size) { struct uref *output = uref_block_splice(uref, 0, upipe_ts_check->output_size); if (unlikely(output == NULL)) { uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } if (!first) uref_flow_delete_discontinuity(output); first = false; if (!upipe_ts_check_check(upipe, output, upump_p)) { uref_free(uref); return; } uref_block_resize(uref, upipe_ts_check->output_size, -1); size -= upipe_ts_check->output_size; } if (!first) uref_flow_delete_discontinuity(uref); if (size == upipe_ts_check->output_size) upipe_ts_check_check(upipe, uref, upump_p); }
/** @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 upipe_rtp_h264_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { size_t bz = 0; if (!ubase_check(uref_block_size(uref, &bz))) { upipe_err(upipe, "fail to get uref block size"); return upipe_rtp_h264_drop(upipe, uref); } uint8_t buf[bz]; int size = bz; if (unlikely(!ubase_check(uref_block_extract(uref, 0, size, buf)))) { upipe_err(upipe, "fail to read from uref"); return upipe_rtp_h264_drop(upipe, uref); } uint8_t s_len; const uint8_t *s = upipe_mpeg_scan(buf, buf + size, &s_len); if (s != buf) { upipe_err(upipe, "uref does not start with a mpeg start code"); return upipe_rtp_h264_drop(upipe, uref); } while (s < buf + size) { uint8_t e_len = 0; const uint8_t *e = upipe_mpeg_scan(s + s_len, buf + size, &e_len); if (!e) e = buf + size; struct uref *part = uref_block_splice(uref, s - buf + s_len + 1, e - (s + s_len + 1)); upipe_rtp_h264_output_nalu(upipe, *(s + s_len), part, upump_p); s = e; s_len = e_len; } uref_free(uref); }
/** @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 outputs audio buffers * * @param upipe description structure of the pipe * @param frame AVFrame structure * @param upump upump structure */ static void upipe_avcdec_output_audio(struct upipe *upipe, AVFrame *frame, struct upump *upump) { struct ubuf *ubuf; struct upipe_avcdec *upipe_avcdec = upipe_avcdec_from_upipe(upipe); struct uref *uref = frame->opaque; int bufsize = -1, avbufsize; size_t size = 0; uint8_t *buf; AVCodecContext *context = upipe_avcdec->context; /* fetch audio sample size (in case it has been reduced) */ avbufsize = av_samples_get_buffer_size(NULL, context->channels, frame->nb_samples, context->sample_fmt, 1); /* if uref has no attached ubuf (ie DR not supported) */ if (unlikely(!uref->ubuf)) { ubuf = ubuf_block_alloc(upipe_avcdec->ubuf_mgr, avbufsize); if (unlikely(!ubuf)) { upipe_throw_aerror(upipe); return; } ubuf_block_write(ubuf, 0, &bufsize, &buf); memcpy(buf, frame->data[0], bufsize); uref_attach_ubuf(uref, ubuf); } /* unmap, reduce block if needed */ uref_block_unmap(uref, 0); uref_block_size(uref, &size); if (unlikely(size != avbufsize)) { uref_block_resize(uref, 0, avbufsize); } /* TODO: set attributes/need a real ubuf_audio structure (?) */ if (!upipe_avcdec->output_flow) { #if 0 struct uref *outflow = uref_sound_flow_alloc_def(upipe_avcdec->uref_mgr, context->channels, av_get_bytes_per_sample(context->sample_fmt)); #else struct uref *outflow = uref_block_flow_alloc_def(upipe_avcdec->uref_mgr, "sound."); #endif uref_sound_flow_set_channels(outflow, context->channels); uref_sound_flow_set_sample_size(outflow, av_get_bytes_per_sample(context->sample_fmt)); uref_sound_flow_set_rate(outflow, context->sample_rate); upipe_avcdec_store_flow_def(upipe, outflow); } /* samples in uref */ uref_sound_flow_set_samples(uref, frame->nb_samples); /* index rap attribute */ upipe_avcdec_set_index_rap(upipe, uref); upipe_avcdec_output(upipe, uref, upump); }
/** @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; }
/** @internal @This merges a PSI section. * * @param upipe description structure of the pipe * @param uref uref pointing to (part of) a PSI section * @param upump_p reference to pump that generated the buffer * @return false if the uref has been entirely consumed */ static bool upipe_ts_psim_merge(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_ts_psim *upipe_ts_psim = upipe_ts_psim_from_upipe(upipe); if (upipe_ts_psim->next_uref != NULL) { struct ubuf *ubuf = ubuf_dup(uref->ubuf); if (unlikely(ubuf == NULL || !ubase_check(uref_block_append(upipe_ts_psim->next_uref, ubuf)))) { upipe_ts_psim_flush(upipe); if (ubuf != NULL) ubuf_free(ubuf); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return false; } } else { /* Check for stuffing */ uint8_t table_id; if (unlikely(!ubase_check(uref_block_extract(uref, 0, 1, &table_id)) || table_id == 0xff)) { return false; } upipe_ts_psim->next_uref = uref_dup(uref); if (unlikely(upipe_ts_psim->next_uref == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return false; } } size_t size = 0; UBASE_FATAL(upipe, uref_block_size(upipe_ts_psim->next_uref, &size)) if (size < PSI_HEADER_SIZE) return false; uint8_t buffer[PSI_HEADER_SIZE]; const uint8_t *psi_header = uref_block_peek(upipe_ts_psim->next_uref, 0, PSI_HEADER_SIZE, buffer); assert(psi_header != NULL); uint16_t length = psi_get_length(psi_header); UBASE_FATAL(upipe, uref_block_peek_unmap(upipe_ts_psim->next_uref, 0, buffer, psi_header)); if (unlikely(!psi_validate(psi_header) || length + PSI_HEADER_SIZE > PSI_PRIVATE_MAX_SIZE)) { upipe_warn(upipe, "wrong PSI header"); upipe_ts_psim_flush(upipe); return false; } if (length + PSI_HEADER_SIZE > size) return false; UBASE_FATAL(upipe, uref_block_resize(upipe_ts_psim->next_uref, 0, length + PSI_HEADER_SIZE)); upipe_ts_psim_output(upipe, upipe_ts_psim->next_uref, upump_p); upipe_ts_psim->next_uref = NULL; if (length + PSI_HEADER_SIZE == size) return false; size_t uref_size = 0; UBASE_FATAL(upipe, uref_block_size(uref, &uref_size)) UBASE_FATAL(upipe, uref_block_resize(uref, length + PSI_HEADER_SIZE - (size - uref_size), -1)); return true; }
/** @internal @This 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); }
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. * * @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; }