/** @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_filter_blend_set_flow_def(struct upipe *upipe, struct uref *flow_def) { if (flow_def == NULL) return UBASE_ERR_INVALID; UBASE_RETURN(uref_flow_match_def(flow_def, "pic.")) 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; } UBASE_RETURN(uref_pic_set_progressive(flow_def_dup)) upipe_input(upipe, flow_def_dup, NULL); return UBASE_ERR_NONE; }
/** @internal @This handles data. * * @param upipe description structure of the pipe * @param uref uref structure describing the picture * @param upump_p reference to pump that generated the buffer * @return true if the packet was handled */ static bool upipe_audiobar_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_audiobar *upipe_audiobar = upipe_audiobar_from_upipe(upipe); const char *def; if (unlikely(ubase_check(uref_flow_get_def(uref, &def)))) { UBASE_FATAL(upipe, uref_sound_flow_get_channels(uref, &upipe_audiobar->channels)) uref_sound_flow_clear_format(uref); UBASE_FATAL(upipe, uref_attr_import(uref, upipe_audiobar->flow_def_config)) uref_pic_flow_clear_format(uref); UBASE_FATAL(upipe, uref_pic_flow_set_planes(uref, 0)) UBASE_FATAL(upipe, uref_pic_flow_set_macropixel(uref, 1)) UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 1, 1, 1, "y8")) UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 2, 1, 1, "u8")) UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 2, 1, 1, "v8")) UBASE_FATAL(upipe, uref_pic_flow_add_plane(uref, 1, 1, 1, "a8")) UBASE_FATAL(upipe, uref_pic_set_progressive(uref)) upipe_audiobar->hsize = upipe_audiobar->vsize = upipe_audiobar->sep_width = upipe_audiobar->pad_width = UINT64_MAX; upipe_audiobar_require_flow_format(upipe, uref); return true; } if (!upipe_audiobar->ubuf_mgr) return false; if (unlikely(upipe_audiobar->hsize == UINT64_MAX)) return false; struct ubuf *ubuf = ubuf_pic_alloc(upipe_audiobar->ubuf_mgr, upipe_audiobar->hsize, upipe_audiobar->vsize); uref_attach_ubuf(uref, ubuf); uint8_t *dst[4]; size_t strides[4]; uint8_t hsubs[4]; uint8_t vsubs[4]; static const char *chroma[4] = { "y8", "u8", "v8", "a8" }; for (int i = 0; i < 4; i++) { if (unlikely(!ubase_check(uref_pic_plane_write(uref, chroma[i], 0, 0, -1, -1, &dst[i])) || !ubase_check(uref_pic_plane_size(uref, chroma[i], &strides[i], &hsubs[i], &vsubs[i], NULL)))) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); uref_free(uref); return true; } } uint8_t alpha = upipe_audiobar->alpha; uint64_t h = upipe_audiobar->vsize; const int hred = h - (iec_scale(-8.) * h); const int hyellow = h - (iec_scale(-18.) * h); uint8_t transparent[4] = { 0x10, 0x80, 0x80, 0 }; uint8_t black[4] = { 0x10, 0x80, 0x80, alpha }; uint8_t red[2][4] = { { 76, 85, 0xff, alpha }, { 37, 106, 191, alpha } }; uint8_t green[2][4] = { { 150, 44, 21, alpha }, { 74, 85, 74, alpha } }; uint8_t yellow[2][4] = { { 226, 1, 148, alpha }, { 112, 64, 138, alpha } }; uint64_t pts = 0; if (unlikely(!ubase_check(uref_clock_get_pts_prog(uref, &pts)))) { upipe_warn(upipe, "unable to read pts"); } for (uint8_t chan = 0; chan < upipe_audiobar->channels; chan++) { double amplitude = 0.; if (unlikely(!ubase_check(uref_amax_get_amplitude(uref, &litude, chan)))) upipe_warn_va(upipe, "unable to get amplitude for channel %"PRIu8", assuming silence", chan); double scale = log10(amplitude) * 20; // IEC-268-18 return time speed is 20dB per 1.7s (+/- .3) if (upipe_audiobar->peak_date[chan]) upipe_audiobar->peak[chan] -= 20 * (pts - upipe_audiobar->peak_date[chan]) / (1.7 * UCLOCK_FREQ); upipe_audiobar->peak_date[chan] = pts; if (scale >= upipe_audiobar->peak[chan]) /* higher than lowered peak */ upipe_audiobar->peak[chan] = scale; else /* Current amplitude can not go below the lowered peak value */ scale = upipe_audiobar->peak[chan]; scale = iec_scale(scale); const int hmax = h - scale * h; for (int row = 0; row < h; row++) { bool bright = row > hmax; const uint8_t *color = row < hred ? red[!bright] : row < hyellow ? yellow[!bright] : green[!bright]; copy_color(dst, strides, hsubs, vsubs, color, row, chan * upipe_audiobar->chan_width, upipe_audiobar->chan_width); if (chan && upipe_audiobar->sep_width) copy_color(dst, strides, hsubs, vsubs, black, row, chan * upipe_audiobar->chan_width - upipe_audiobar->sep_width / 2, upipe_audiobar->sep_width); if (chan == upipe_audiobar->channels - 1 && upipe_audiobar->pad_width) copy_color(dst, strides, hsubs, vsubs, transparent, row, (chan + 1) * upipe_audiobar->chan_width, upipe_audiobar->pad_width); } } /* dB marks */ for (int i = 1; i <= 6; i++) { int row = h - (iec_scale(-10 * i) * h); copy_color(dst, strides, hsubs, vsubs, black, row, 0, upipe_audiobar->hsize); } for (int i = 0; i < 4; i++) ubuf_pic_plane_unmap(ubuf, chroma[i], 0, 0, -1, -1); upipe_audiobar_output(upipe, uref, upump_p); return true; }
/** avcdec callback */ static int avcdec_catch(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { if (event != UPROBE_NEED_OUTPUT) return uprobe_throw_next(uprobe, upipe, event, args); struct uref *flow_def = va_arg(args, struct uref *); uint64_t hsize, vsize, wanted_hsize; struct urational sar; bool progressive; if (unlikely(!ubase_check(uref_pic_flow_get_hsize(flow_def, &hsize)) || !ubase_check(uref_pic_flow_get_vsize(flow_def, &vsize)) || !ubase_check(uref_pic_flow_get_sar(flow_def, &sar)))) { upipe_err_va(upipe, "incompatible flow def"); upipe_release(upipe_source); return UBASE_ERR_UNHANDLED; } wanted_hsize = (hsize * sar.num / sar.den / 2) * 2; progressive = ubase_check(uref_pic_get_progressive(flow_def)); struct uref *flow_def2 = uref_dup(flow_def); upipe_use(upipe); if (!progressive) { uref_pic_set_progressive(flow_def2); struct upipe *deint = upipe_void_alloc_output(upipe, upipe_filter_blend_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "deint")); assert(deint != NULL); upipe_release(upipe); upipe = deint; } if (wanted_hsize != hsize) { uref_pic_flow_set_hsize(flow_def2, wanted_hsize); struct upipe *sws = upipe_flow_alloc_output(upipe, upipe_sws_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "sws"), flow_def2); assert(sws != NULL); upipe_release(upipe); upipe = sws; } uref_pic_flow_clear_format(flow_def2); uref_flow_set_def(flow_def2, "block.mjpeg.pic."); struct upipe *jpegenc = upipe_flow_alloc_output(upipe, upipe_avcenc_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), loglevel, "jpeg"), flow_def2); assert(jpegenc != NULL); upipe_release(upipe); upipe_set_option(jpegenc, "qmax", "2"); upipe = jpegenc; struct upipe *urefprobe = upipe_void_alloc_output(upipe, upipe_probe_uref_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_uref), loglevel, "urefprobe")); assert(urefprobe != NULL); upipe_release(upipe); upipe = urefprobe; struct upipe *fsink = upipe_void_alloc_output(upipe, upipe_fsink_mgr, uprobe_pfx_alloc_va(uprobe_use(logger), ((loglevel > UPROBE_LOG_DEBUG) ? UPROBE_LOG_WARNING : loglevel), "jpegsink")); assert(fsink != NULL); upipe_release(upipe); upipe_fsink_set_path(fsink, dstpath, UPIPE_FSINK_OVERWRITE); upipe = fsink; uref_free(flow_def2); upipe_release(upipe); return UBASE_ERR_NONE; }
/** @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; }
/** @internal @This handles the input uref. * * @param upipe description structure of the pipe * @param uref input uref * @param upump_p reference to pump that generated the buffer */ static void upipe_vblk_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_vblk *upipe_vblk = upipe_vblk_from_upipe(upipe); struct uref *flow_def = upipe_vblk->flow_def; struct uref *input_flow_def = upipe_vblk->input_flow_def; if (uref->ubuf) { upipe_vblk_output(upipe, uref, upump_p); return; } if (unlikely(!input_flow_def)) { upipe_warn(upipe, "no input flow definition"); uref_free(uref); return; } if (unlikely(!flow_def)) { upipe_warn(upipe, "no output flow definition"); uref_free(uref); return; } if (unlikely(!upipe_vblk->ubuf_mgr)) { upipe_warn(upipe, "no ubuf manager set"); uref_free(uref); return; } if (unlikely(!upipe_vblk->ubuf)) { upipe_verbose(upipe, "allocate blank picture"); uint64_t hsize, vsize; ubase_assert(uref_pic_flow_get_hsize(upipe_vblk->flow_def, &hsize)); ubase_assert(uref_pic_flow_get_vsize(upipe_vblk->flow_def, &vsize)); upipe_vblk->ubuf = ubuf_pic_alloc(upipe_vblk->ubuf_mgr, hsize, vsize); if (unlikely(!upipe_vblk->ubuf)) { upipe_err(upipe, "fail to allocate picture"); uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } ubuf_pic_clear(upipe_vblk->ubuf, 0, 0, -1, -1, 1); } struct ubuf *ubuf = ubuf_dup(upipe_vblk->ubuf); if (unlikely(!ubuf)) { upipe_err(upipe, "fail to duplicate blank picture"); uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } uref_attach_ubuf(uref, ubuf); if (ubase_check(uref_pic_get_progressive(flow_def))) uref_pic_set_progressive(uref); upipe_vblk_output(upipe, uref, upump_p); }
/** @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; }