From 72655e36e5ad3ba39145fbc434e0912c0d7eb526 Mon Sep 17 00:00:00 2001 From: James Darnley Date: Fri, 30 Oct 2020 13:00:40 +0100 Subject: [PATCH 1/2] upipe-modules: add upipe_pad A module to pad picture urefs with blank space. --- include/upipe-modules/Makefile.am | 1 + include/upipe-modules/upipe_pad.h | 53 ++++++ lib/upipe-modules/Makefile.am | 1 + lib/upipe-modules/upipe_pad.c | 301 ++++++++++++++++++++++++++++++ 4 files changed, 356 insertions(+) create mode 100644 include/upipe-modules/upipe_pad.h create mode 100644 lib/upipe-modules/upipe_pad.c diff --git a/include/upipe-modules/Makefile.am b/include/upipe-modules/Makefile.am index 158d37349..e8b7d5e54 100644 --- a/include/upipe-modules/Makefile.am +++ b/include/upipe-modules/Makefile.am @@ -92,4 +92,5 @@ myinclude_HEADERS = \ uref_graph_flow.h \ uref_graph.h \ upipe_graph.h \ + upipe_pad.h \ $(NULL) diff --git a/include/upipe-modules/upipe_pad.h b/include/upipe-modules/upipe_pad.h new file mode 100644 index 000000000..16e5c750c --- /dev/null +++ b/include/upipe-modules/upipe_pad.h @@ -0,0 +1,53 @@ +/* + * Pad picture urefs with blank space. + * + * Copyright (C) 2020 Open Broadcast Systems Ltd. + * + * Authors: James Darnley + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module to pad picture urefs with blank space. + */ + +#ifndef _UPIPE_MODULES_UPIPE_PAD_H_ +#define _UPIPE_MODULES_UPIPE_PAD_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @This is the signature of a pad pipe. */ +#define UPIPE_PAD_SIGNATURE UBASE_FOURCC('p','a','d',' ') + +/** @This returns the pad pipe manager. + * + * @return a pointer to the pad pipe manager + */ +struct upipe_mgr *upipe_pad_mgr_alloc(void); + +#ifdef __cplusplus +} +#endif +#endif /* !_UPIPE_MODULES_UPIPE_PAD_H_ */ diff --git a/lib/upipe-modules/Makefile.am b/lib/upipe-modules/Makefile.am index 66c7de906..af726ed26 100644 --- a/lib/upipe-modules/Makefile.am +++ b/lib/upipe-modules/Makefile.am @@ -82,6 +82,7 @@ libupipe_modules_la_SOURCES = \ upipe_discard_blocking.c \ upipe_audio_merge.c \ upipe_graph.c \ + upipe_pad.c \ $(NULL) if HAVE_WRITEV diff --git a/lib/upipe-modules/upipe_pad.c b/lib/upipe-modules/upipe_pad.c new file mode 100644 index 000000000..7c13b363f --- /dev/null +++ b/lib/upipe-modules/upipe_pad.c @@ -0,0 +1,301 @@ +/* + * Pad picture urefs with blank space. + * + * Copyright (c) 2020 Open Broadcast Systems Ltd. + * + * Authors: James Darnley + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + * @short Upipe module to pad picture urefs with blank space. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/** we only accept pictures */ +#define EXPECTED_FLOW_DEF "pic." + +struct upipe_pad { + /** refcount management structure */ + struct urefcount urefcount; + + /** ubuf manager */ + struct ubuf_mgr *ubuf_mgr; + /** flow format packet */ + struct uref *flow_format; + /** ubuf manager request */ + struct urequest ubuf_mgr_request; + + /** output pipe */ + struct upipe *output; + /** flow_definition packet */ + struct uref *flow_def; + /** output state */ + enum upipe_helper_output_state output_state; + /** list of output requests */ + struct uchain request_list; + + /** temporary uref storage (used during urequest) */ + struct uchain urefs; + /** nb urefs in storage */ + unsigned int nb_urefs; + /** max urefs in storage */ + unsigned int max_urefs; + /** list of blockers (used during udeal) */ + struct uchain blockers; + + /** public upipe structure */ + struct upipe upipe; + + /* flow_def given at alloc describing how to pad the picture */ + uint64_t w, h, l, r, t, b; +}; + +/** @hidden */ +static bool upipe_pad_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p); +/** @hidden */ +static int upipe_pad_check(struct upipe *upipe, struct uref *flow_format); + +UPIPE_HELPER_UPIPE(upipe_pad, upipe, UPIPE_PAD_SIGNATURE); +UPIPE_HELPER_UREFCOUNT(upipe_pad, urefcount, upipe_pad_free); +UPIPE_HELPER_FLOW(upipe_pad, EXPECTED_FLOW_DEF); +UPIPE_HELPER_INPUT(upipe_pad, urefs, nb_urefs, max_urefs, blockers, upipe_pad_handle) +UPIPE_HELPER_OUTPUT(upipe_pad, output, flow_def, output_state, request_list) +UPIPE_HELPER_UBUF_MGR(upipe_pad, ubuf_mgr, flow_format, ubuf_mgr_request, upipe_pad_check, + upipe_pad_register_output_request, upipe_pad_unregister_output_request) + +/** @internal @This allocates a pad 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_pad_alloc(struct upipe_mgr *mgr, + struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + struct uref *flow_def; + struct upipe *upipe = upipe_pad_alloc_flow(mgr, uprobe, signature, args, &flow_def); + if (unlikely(upipe == NULL)) + return NULL; + + struct upipe_pad *upipe_pad = upipe_pad_from_upipe(upipe); + + upipe_pad_init_urefcount(upipe); + upipe_pad_init_input(upipe); + upipe_pad_init_output(upipe); + upipe_pad_init_ubuf_mgr(upipe); + + /* TODO: support more options than only the pad attributes. */ + + uint64_t l = 0, r = 0, t = 0, b = 0; + if (!ubase_check(uref_pic_get_lpadding(flow_def, &l)) + || !ubase_check(uref_pic_get_rpadding(flow_def, &r)) + || !ubase_check(uref_pic_get_tpadding(flow_def, &t)) + || !ubase_check(uref_pic_get_bpadding(flow_def, &b))) + return NULL; + upipe_pad->l = l; upipe_pad->r = r; upipe_pad->t = t; upipe_pad->b = b; + upipe_pad->w = upipe_pad->h = 0; + + uref_free(flow_def); + upipe_throw_ready(upipe); + return upipe; +} + +/** @internal @This frees a pad pipe. + * + * @param upipe description structure of the pipe + */ +static void upipe_pad_free(struct upipe *upipe) +{ + upipe_throw_dead(upipe); + upipe_pad_clean_urefcount(upipe); + upipe_pad_clean_input(upipe); + upipe_pad_clean_output(upipe); + upipe_pad_clean_ubuf_mgr(upipe); + upipe_pad_free_flow(upipe); +} + +/** @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_pad_set_flow_def(struct upipe *upipe, struct uref *flow_def) +{ + struct upipe_pad *upipe_pad = upipe_pad_from_upipe(upipe); + if (flow_def == NULL) + return UBASE_ERR_INVALID; + UBASE_RETURN(uref_flow_match_def(flow_def, EXPECTED_FLOW_DEF)); + + uint64_t w, h; + UBASE_RETURN(uref_pic_flow_get_hsize(flow_def, &w)); + UBASE_RETURN(uref_pic_flow_get_vsize(flow_def, &h)); + upipe_pad->w = w += upipe_pad->l + upipe_pad->r; + upipe_pad->h = h += upipe_pad->t + upipe_pad->b; + + struct uref *flow_def_dst = uref_dup(flow_def); + UBASE_ALLOC_RETURN(flow_def_dst); + UBASE_RETURN(uref_pic_flow_set_hsize(flow_def_dst, w)); + UBASE_RETURN(uref_pic_flow_set_vsize(flow_def_dst, h)); + + upipe_pad_require_ubuf_mgr(upipe, flow_def_dst); + 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 false if the input must be blocked + */ +static bool upipe_pad_handle(struct upipe *upipe, struct uref *uref, struct upump **upump_p) +{ + struct upipe_pad *upipe_pad = upipe_pad_from_upipe(upipe); + if (!upipe_pad->ubuf_mgr) { + upipe_warn(upipe, "no ubuf_mgr, holding input uref"); + return false; + } + + struct ubuf *ubuf_dst = ubuf_pic_alloc(upipe_pad->ubuf_mgr, upipe_pad->w, upipe_pad->h); + if (!ubuf_dst) { + uref_free(uref); + upipe_throw_error(upipe, UBASE_ERR_ALLOC); + return true; + } + ubuf_pic_clear(ubuf_dst, 0, 0, -1, -1, 1); + + uint64_t w = upipe_pad->w - upipe_pad->l - upipe_pad->r; + uint64_t h = upipe_pad->h - upipe_pad->t - upipe_pad->b; + UBASE_ERROR(upipe, ubuf_pic_blit(ubuf_dst, uref->ubuf, upipe_pad->l, upipe_pad->t, + 0, 0, w, h, 0, 0)); + + uref_attach_ubuf(uref, ubuf_dst); + upipe_pad_output(upipe, uref, upump_p); + return true; +} + +/** @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_pad_check(struct upipe *upipe, struct uref *flow_format) +{ + struct upipe_pad *upipe_pad = upipe_pad_from_upipe(upipe); + if (flow_format != NULL) + upipe_pad_store_flow_def(upipe, flow_format); + if (upipe_pad->flow_def == NULL) + return UBASE_ERR_NONE; + + bool was_buffered = !upipe_pad_check_input(upipe); + upipe_pad_output_input(upipe); + upipe_pad_unblock_input(upipe); + if (was_buffered && upipe_pad_check_input(upipe)) { + /* All packets have been output, release again the pipe that has been + * used in @ref upipe_pad_input. */ + upipe_release(upipe); + } + return UBASE_ERR_NONE; +} + +/** @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_pad_input(struct upipe *upipe, struct uref *uref, + struct upump **upump_p) +{ + if (!upipe_pad_check_input(upipe)) { + upipe_pad_hold_input(upipe, uref); + upipe_pad_block_input(upipe, upump_p); + } else if (!upipe_pad_handle(upipe, uref, upump_p)) { + upipe_pad_hold_input(upipe, uref); + upipe_pad_block_input(upipe, upump_p); + /* Increment upipe refcount to avoid disappearing before all packets + * have been sent. */ + upipe_use(upipe); + } +} + +/** @internal @This handles the pipe control commands. + * + * @param upipe description structure of the pipe + * @param command control command to handle + * @param args optional arguments + * @return an error code + */ +static int upipe_pad_control(struct upipe *upipe, int command, va_list args) +{ + UBASE_HANDLED_RETURN(upipe_pad_control_ubuf_mgr(upipe, command, args)); + UBASE_HANDLED_RETURN(upipe_pad_control_output(upipe, command, args)); + switch (command) { + default: + return UBASE_ERR_UNHANDLED; + + case UPIPE_SET_FLOW_DEF: { + struct uref *flow = va_arg(args, struct uref *); + return upipe_pad_set_flow_def(upipe, flow); + } + } +} + +/** @internal @This is the static pipe manager. */ +static struct upipe_mgr upipe_pad_mgr = { + .refcount = NULL, + .signature = UPIPE_PAD_SIGNATURE, + .upipe_alloc = upipe_pad_alloc, + .upipe_input = upipe_pad_input, + .upipe_control = upipe_pad_control, +}; + +/** @This returns the pad pipe manager. + * + * @return a pointer to the pipe manager + */ +struct upipe_mgr *upipe_pad_mgr_alloc(void) +{ + return &upipe_pad_mgr; +} From 3e8b7d8aa2bb2bf062fdc6d22dd398e61016dfcd Mon Sep 17 00:00:00 2001 From: James Darnley Date: Fri, 30 Oct 2020 13:10:00 +0100 Subject: [PATCH 2/2] tests: add upipe_pad test --- tests/Makefile.am | 3 + tests/upipe_pad_test.c | 319 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 tests/upipe_pad_test.c diff --git a/tests/Makefile.am b/tests/Makefile.am index d94bff28e..5bcc40965 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -97,6 +97,7 @@ check_PROGRAMS = \ upipe_match_attr_test \ upipe_blit_test \ upipe_crop_test \ + upipe_pad_test \ upipe_audio_split_test \ upipe_videocont_test \ upipe_audiocont_test \ @@ -159,6 +160,7 @@ TESTS = \ upipe_match_attr_test \ upipe_blit_test \ upipe_crop_test \ + upipe_pad_test \ upipe_audio_split_test \ upipe_videocont_test \ upipe_audiocont_test \ @@ -451,6 +453,7 @@ upipe_chunk_stream_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libup upipe_htons_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libupipe_modules.la upipe_blit_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libupipe_modules.la upipe_crop_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libupipe_modules.la +upipe_pad_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libupipe_modules.la upipe_qt_html_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-qt/libupipe_qt.la -L/usr/lib/x86_64-linux-gnu -lQtCore -lQtGui -lQtWebKit -lpthread $(top_builddir)/lib/upipe-modules/libupipe_modules.la $(top_builddir)/lib/upump-ev/libupump_ev.la $(top_builddir)/lib/upipe-pthread/libupipe_pthread.la -lev $(top_builddir)/lib/upump-ev/libupump_ev.la upipe_audio_split_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libupipe_modules.la upipe_videocont_test_LDADD = $(LDADD) $(top_builddir)/lib/upipe-modules/libupipe_modules.la diff --git a/tests/upipe_pad_test.c b/tests/upipe_pad_test.c new file mode 100644 index 000000000..509d40d0f --- /dev/null +++ b/tests/upipe_pad_test.c @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2020 Open Broadcast Systems Ltd. + * + * Authors: James Darnley + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject + * to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define UDICT_POOL_DEPTH 0 +#define UREF_POOL_DEPTH 0 +#define UBUF_POOL_DEPTH 0 +#define UPROBE_LOG_LEVEL UPROBE_LOG_VERBOSE + +#define PAD_L 2 +#define PAD_R 4 +#define PAD_T 5 +#define PAD_B 1 + +#define INPUT_W 32 +#define INPUT_H 16 + +#define TOTAL_W INPUT_W + PAD_L + PAD_R +#define TOTAL_H INPUT_H + PAD_T + PAD_B + +/** definition of our uprobe */ +static int catch(struct uprobe *uprobe, struct upipe *upipe, + int event, va_list args) +{ + switch (event) { + case UPROBE_READY: + case UPROBE_DEAD: + case UPROBE_NEW_FLOW_DEF: + break; + default: + assert(0); + break; + } + return UBASE_ERR_NONE; +} + +/* fill picture with some reference */ +static void fill_in(struct uref *uref, const char *chroma, uint8_t val) +{ + uint8_t hsub, vsub, macropixel_size; + size_t hsize, vsize, stride; + uint8_t *buffer; + ubase_assert(uref_pic_plane_write(uref, chroma, 0, 0, -1, -1, &buffer)); + ubase_assert(uref_pic_plane_size(uref, chroma, &stride, &hsub, &vsub, ¯opixel_size)); + assert(buffer != NULL); + ubase_assert(uref_pic_size(uref, &hsize, &vsize, NULL)); + hsize /= hsub; + hsize *= macropixel_size; + vsize /= vsub; + for (int y = 0; y < vsize; y++) { + for (int x = 0; x < hsize; x++) + buffer[x] = val; + buffer += stride; + } + uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1); +} + +/* check a chroma */ +static void check_chroma(struct uref *uref, const char *chroma, uint8_t val) +{ + uint8_t hsub, vsub, macropixel_size; + size_t hsize, vsize, stride; + const uint8_t *buffer; + int x, y; + + ubase_assert(uref_pic_plane_read(uref, chroma, 0, 0, -1, -1, &buffer)); + ubase_assert(uref_pic_plane_size(uref, chroma, &stride, &hsub, &vsub, ¯opixel_size)); + ubase_assert(uref_pic_size(uref, &hsize, &vsize, NULL)); + hsize /= hsub; + hsize *= macropixel_size; + vsize /= vsub; + + for (y = 0; y < vsize; y++) { + for (x = 0; x < hsize; x++) { + assert(buffer[x] == val); + } + buffer += stride; + } + + uref_pic_plane_unmap(uref, chroma, 0, 0, -1, -1); +} + +/** helper phony pipe */ +static struct upipe *test_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, + uint32_t signature, va_list args) +{ + struct upipe *upipe = malloc(sizeof(struct upipe)); + upipe_init(upipe, mgr, uprobe); + upipe_throw_ready(upipe); + return upipe; +} + +/** helper phony pipe */ +static void test_input(struct upipe *upipe, struct uref *uref, + struct upump **upump_p) +{ + assert(uref != NULL); + upipe_dbg(upipe, "===> received input uref"); + uref_dump(uref, upipe->uprobe); + + /* Check left. */ + ubase_assert(uref_pic_resize(uref, 0, 0, PAD_L, TOTAL_H)); + check_chroma(uref, "y8", 0); + check_chroma(uref, "u8", 0x80); + check_chroma(uref, "v8", 0x80); + ubase_assert(uref_pic_resize(uref, 0, 0, TOTAL_W, TOTAL_H)); + + /* Check top. */ + ubase_assert(uref_pic_resize(uref, 0, 0, TOTAL_W, PAD_T)); + check_chroma(uref, "y8", 0); + check_chroma(uref, "u8", 0x80); + check_chroma(uref, "v8", 0x80); + ubase_assert(uref_pic_resize(uref, 0, 0, TOTAL_W, TOTAL_H)); + + /* Check middle. */ + ubase_assert(uref_pic_resize(uref, PAD_L, PAD_T, INPUT_W, INPUT_H)); + check_chroma(uref, "y8", 1); + check_chroma(uref, "u8", 128); + check_chroma(uref, "v8", 255); + ubase_assert(uref_pic_resize(uref, -PAD_L, -PAD_T, TOTAL_W, TOTAL_H)); + + /* Check right. */ + ubase_assert(uref_pic_resize(uref, INPUT_W + PAD_L, 0, PAD_R, TOTAL_H)); + check_chroma(uref, "y8", 0); + check_chroma(uref, "u8", 0x80); + check_chroma(uref, "v8", 0x80); + ubase_assert(uref_pic_resize(uref, -(INPUT_W + PAD_L), 0, TOTAL_W, TOTAL_H)); + + /* Check bottom. */ + ubase_assert(uref_pic_resize(uref, 0, INPUT_H + PAD_T, TOTAL_W, PAD_B)); + check_chroma(uref, "y8", 0); + check_chroma(uref, "u8", 0x80); + check_chroma(uref, "v8", 0x80); + ubase_assert(uref_pic_resize(uref, 0, -(INPUT_H + PAD_T), TOTAL_W, TOTAL_H)); + + uref_free(uref); +} + +/** helper phony pipe */ +static int test_control(struct upipe *upipe, int command, va_list args) +{ + switch (command) { + case UPIPE_SET_FLOW_DEF: { + struct uref *flow_def = va_arg(args, struct uref *); + ubase_assert(uref_flow_match_def(flow_def, "pic.")); + ubase_assert(uref_pic_flow_match_hsize(flow_def, TOTAL_W, TOTAL_W)); + ubase_assert(uref_pic_flow_match_vsize(flow_def, TOTAL_H, TOTAL_H)); + ubase_assert(uref_pic_flow_check_chroma(flow_def, 1, 1, 1, "y8")); + ubase_assert(uref_pic_flow_check_chroma(flow_def, 2, 1, 1, "u8")); + ubase_assert(uref_pic_flow_check_chroma(flow_def, 2, 1, 1, "v8")); + return UBASE_ERR_NONE; + } + case UPIPE_REGISTER_REQUEST: { + struct urequest *urequest = va_arg(args, struct urequest *); + return upipe_throw_provide_request(upipe, urequest); + } + case UPIPE_UNREGISTER_REQUEST: + return UBASE_ERR_NONE; + default: + assert(0); + return UBASE_ERR_UNHANDLED; + } +} + +/** helper phony pipe */ +static void test_free(struct upipe *upipe) +{ + upipe_dbg(upipe, "releasing pipe"); + upipe_throw_dead(upipe); + upipe_clean(upipe); + free(upipe); +} + +/** helper phony pipe */ +static struct upipe_mgr test_mgr = { + .refcount = NULL, + .signature = 0, + .upipe_alloc = test_alloc, + .upipe_input = test_input, + .upipe_control = test_control +}; + +int main(int argc, char **argv) +{ + printf("Compiled %s %s - %s\n", __DATE__, __TIME__, __FILE__); + + /* uref and mem management */ + struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); + assert(umem_mgr != NULL); + struct udict_mgr *udict_mgr = + udict_inline_mgr_alloc(UDICT_POOL_DEPTH, umem_mgr, -1, -1); + assert(udict_mgr != NULL); + struct uref_mgr *uref_mgr = + uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, 0); + assert(uref_mgr != NULL); + + struct ubuf_mgr *pic_mgr = ubuf_pic_mem_mgr_alloc_fourcc(UBUF_POOL_DEPTH, + UBUF_POOL_DEPTH, umem_mgr, "YV16", 0, 0, 0, 0, 0, 0); + assert(pic_mgr != NULL); + + /* uprobe stuff */ + struct uprobe uprobe; + uprobe_init(&uprobe, catch, NULL); + struct uprobe *logger = uprobe_stdio_alloc(&uprobe, stdout, + UPROBE_LOG_LEVEL); + assert(logger != NULL); + logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, 0, 0); + assert(logger != NULL); + + /* build pad pipe */ + struct upipe_mgr *upipe_pad_mgr = upipe_pad_mgr_alloc(); + assert(upipe_pad_mgr); + + struct uref *flow_def = uref_alloc(uref_mgr); + assert(flow_def); + ubase_assert(uref_flow_set_def(flow_def, "pic.")); + ubase_assert(uref_pic_set_lpadding(flow_def, PAD_L)); + ubase_assert(uref_pic_set_rpadding(flow_def, PAD_R)); + ubase_assert(uref_pic_set_tpadding(flow_def, PAD_T)); + ubase_assert(uref_pic_set_bpadding(flow_def, PAD_B)); + + struct upipe *pad = upipe_flow_alloc(upipe_pad_mgr, + uprobe_pfx_alloc(uprobe_use(logger), UPROBE_LOG_LEVEL, "pad"), + flow_def); + assert(pad != NULL); + uref_free(flow_def); + + /* build phony pipe */ + struct upipe *test = upipe_void_alloc(&test_mgr, + uprobe_pfx_alloc(uprobe_use(logger), UPROBE_LOG_LEVEL, "test")); + assert(test != NULL); + ubase_assert(upipe_set_output(pad, test)); + + flow_def = uref_pic_flow_alloc_def(uref_mgr, 1); + assert(flow_def != NULL); + ubase_assert(uref_pic_flow_add_plane(flow_def, 1, 1, 1, "y8")); + ubase_assert(uref_pic_flow_add_plane(flow_def, 2, 1, 1, "u8")); + ubase_assert(uref_pic_flow_add_plane(flow_def, 2, 1, 1, "v8")); + ubase_assert(uref_pic_flow_set_hsize(flow_def, INPUT_W)); + ubase_assert(uref_pic_flow_set_vsize(flow_def, INPUT_H)); + ubase_assert(upipe_set_flow_def(pad, flow_def)); + uref_free(flow_def); + + struct uref *uref; + uref = uref_pic_alloc(uref_mgr, pic_mgr, INPUT_W, INPUT_H); + assert(uref != NULL); + uref_pic_set_progressive(uref); + fill_in(uref, "y8", 1); + fill_in(uref, "u8", 128); + fill_in(uref, "v8", 255); + upipe_input(pad, uref, NULL); + + /* release pad pipe and subpipes */ + upipe_release(pad); + test_free(test); + + /* release managers */ + upipe_mgr_release(upipe_pad_mgr); // no-op + ubuf_mgr_release(pic_mgr); + uref_mgr_release(uref_mgr); + umem_mgr_release(umem_mgr); + udict_mgr_release(udict_mgr); + uprobe_release(logger); + uprobe_clean(&uprobe); + + return 0; +}