/** @internal @This handles inner reader pipe events. * * @param uprobe structure used to raise events * @param inner pointer to inner pipe * @param event event thrown * @param args optional arguments * @return an error code */ static int probe_reader(struct uprobe *uprobe, struct upipe *inner, int event, va_list args) { struct upipe_hls *upipe_hls = upipe_hls_from_probe_reader(uprobe); struct upipe *upipe = upipe_hls_to_upipe(upipe_hls); if (event >= UPROBE_LOCAL) return UBASE_ERR_NONE; if (event == UPROBE_NEED_OUTPUT) { struct uref *flow_format = va_arg(args, struct uref *); const char *def; UBASE_RETURN(uref_flow_get_def(flow_format, &def)); struct uref *flow_format_dup = uref_dup(flow_format); if (unlikely(!flow_format_dup)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return UBASE_ERR_ALLOC; } upipe_hls_store_flow_def(upipe, flow_format_dup); if (!strcmp(def, "block.m3u.playlist.")) { struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc(); struct upipe *output = upipe_void_alloc_output( inner, upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_null), UPROBE_LOG_VERBOSE, "null")); upipe_mgr_release(upipe_null_mgr); upipe_release(output); upipe_split_throw_update(upipe); return UBASE_ERR_NONE; } else if (!strcmp(def, "block.m3u.master.")) { struct upipe_mgr *upipe_hls_master_mgr = upipe_hls_master_mgr_alloc(); UBASE_ALLOC_RETURN(upipe_hls_master_mgr); struct upipe *output = upipe_void_alloc_output( inner, upipe_hls_master_mgr, uprobe_pfx_alloc(uprobe_use(&upipe_hls->probe_master), UPROBE_LOG_VERBOSE, "master")); upipe_mgr_release(upipe_hls_master_mgr); UBASE_ALLOC_RETURN(output); upipe_hls_store_bin_output(upipe, output); return UBASE_ERR_NONE; } else upipe_warn_va(upipe, "unsupported flow format %s", def); return UBASE_ERR_INVALID; } return upipe_throw_proxy(upipe, inner, event, args); }
/** @internal @This catches events of the dec queue source. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_dec_qsrc(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_SOURCE_END: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_dec_qsrc_s); upipe_flush(glxplayer->upipe_glx_qsink); upipe_release(glxplayer->upipe_glx_qsink); return UBASE_ERR_NONE; } case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_dec_qsrc_s); struct upipe *avcdec = upipe_void_alloc_output(upipe, glxplayer->upipe_avcdec_mgr, uprobe_pfx_alloc_va( uprobe_use(&glxplayer->uprobe_avcdec_s), glxplayer->loglevel, "avcdec")); if (unlikely(avcdec == NULL)) return UBASE_ERR_ALLOC; upipe_set_option(avcdec, "threads", "2"); upipe_release(avcdec); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** @internal @This catches events of the qsrc of the glx (main) thread. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_glx_qsrc(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_SOURCE_END: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_glx_qsrc_s); upipe_release(upipe); pthread_join(glxplayer->src_thread_id, NULL); if (glxplayer->trickp) upipe_release(glxplayer->upipe_trickp); free(glxplayer->uri); return UBASE_ERR_NONE; } case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_glx_qsrc_s); struct upipe *trickp_pic; if (glxplayer->trickp) { glxplayer->upipe_trickp = upipe_void_alloc(glxplayer->upipe_trickp_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "trickp")); if (unlikely(glxplayer->upipe_trickp == NULL)) return UBASE_ERR_ALLOC; upipe_attach_uclock(glxplayer->upipe_trickp); trickp_pic = upipe_void_alloc_output_sub(upipe, glxplayer->upipe_trickp, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "trickp pic")); if (unlikely(trickp_pic == NULL)) return UBASE_ERR_ALLOC; } else trickp_pic = upipe; /* glx sink */ struct upipe *glx_sink = upipe_void_alloc_output(trickp_pic, glxplayer->upipe_glx_mgr, uprobe_gl_sink_cube_alloc( uprobe_pfx_alloc( uprobe_use(&glxplayer->uprobe_glx_s), glxplayer->loglevel, "glx"))); if (glxplayer->trickp) upipe_release(trickp_pic); if (unlikely(glx_sink == NULL)) return UBASE_ERR_ALLOC; upipe_glx_sink_init(glx_sink, 0, 0, 800, 480); upipe_attach_uclock(glx_sink); upipe_release(glx_sink); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** @internal @This catches events of the avcdec. * * @param uprobe pointer to probe * @param upipe pointer to pipe throwing the event * @param event event thrown * @param args optional event-specific parameters * @return an error code */ static int upipe_glxplayer_catch_avcdec(struct uprobe *uprobe, struct upipe *upipe, int event, va_list args) { switch (event) { case UPROBE_NEED_OUTPUT: { struct upipe_glxplayer *glxplayer = container_of(uprobe, struct upipe_glxplayer, uprobe_avcdec_s); struct uref *flow_def = va_arg(args, struct uref *); struct upipe *deint = upipe_void_alloc_output(upipe, glxplayer->upipe_filter_blend_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "deint")); if (unlikely(deint == NULL)) return UBASE_ERR_ALLOC; struct uref *output_flow = uref_dup(flow_def); if (unlikely(output_flow == NULL)) return UBASE_ERR_ALLOC; uref_pic_flow_clear_format(output_flow); if (unlikely(!ubase_check(uref_pic_flow_set_macropixel(output_flow, 1)) || !ubase_check(uref_pic_flow_set_planes(output_flow, 0)) || !ubase_check(uref_pic_flow_add_plane(output_flow, 1, 1, 3, "r8g8b8")))) { uref_free(output_flow); return UBASE_ERR_ALLOC; } struct upipe *yuvrgb = upipe_flow_alloc_output(deint, glxplayer->upipe_sws_mgr, uprobe_pfx_alloc_va(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "rgb"), output_flow); assert(yuvrgb != NULL); uref_free(output_flow); upipe_release(deint); glxplayer->upipe_glx_qsink = upipe_qsink_alloc(glxplayer->upipe_qsink_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "glx qsink"), glxplayer->upipe_glx_qsrc); if (unlikely(glxplayer->upipe_glx_qsink == NULL)) return UBASE_ERR_ALLOC; upipe_set_output(yuvrgb, glxplayer->upipe_glx_qsink); upipe_release(yuvrgb); return UBASE_ERR_NONE; } default: return uprobe_throw_next(uprobe, upipe, event, args); } }
/** split callback */ static int split_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); upipe_release(upipe_split_output); upipe_split_output = upipe_use(upipe); struct upipe *avcdec = upipe_void_alloc_output(upipe, upipe_avcdec_mgr, uprobe_pfx_alloc_va(uprobe_use(&uprobe_avcdec), loglevel, "avcdec")); if (avcdec == NULL) { upipe_err_va(upipe, "incompatible flow def"); upipe_release(upipe_source); return UBASE_ERR_UNHANDLED; } upipe_release(avcdec); return UBASE_ERR_NONE; }
int main(int argc, char **argv) { int opt; /* parse options */ while ((opt = getopt(argc, argv, "dqD:")) != -1) { switch (opt) { case 'd': if (loglevel > 0) loglevel--; break; case 'q': if (loglevel < UPROBE_LOG_ERROR) loglevel++; break; case 'D': dump = optarg; break; default: usage(argv[0]); } } if (optind >= argc - 1) { usage(argv[0]); } srcpath = argv[optind++]; dstpath = argv[optind++]; /* choose log fd */ logstream = stderr; /* setup environnement */ struct umem_mgr *umem_mgr = umem_alloc_mgr_alloc(); struct udict_mgr *udict_mgr = udict_inline_mgr_alloc(UDICT_POOL_DEPTH, umem_mgr, -1, -1); uref_mgr = uref_std_mgr_alloc(UREF_POOL_DEPTH, udict_mgr, 0); struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); /* default probe */ logger = uprobe_stdio_alloc(NULL, logstream, loglevel); assert(logger != NULL); logger = uprobe_uref_mgr_alloc(logger, uref_mgr); assert(logger != NULL); logger = uprobe_upump_mgr_alloc(logger, upump_mgr); assert(logger != NULL); logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH, UBUF_POOL_DEPTH); assert(logger != NULL); uref_mgr_release(uref_mgr); upump_mgr_release(upump_mgr); /* split probe */ struct uprobe uprobe_catch; uprobe_init(&uprobe_catch, split_catch, uprobe_use(logger)); /* other probes */ uprobe_init(&uprobe_avcdec, avcdec_catch, uprobe_use(logger)); uprobe_init(&uprobe_uref, uref_catch, uprobe_use(logger)); /* upipe-av */ upipe_av_init(true, uprobe_use(logger)); /* global pipe managers */ upipe_avcdec_mgr = upipe_avcdec_mgr_alloc(); upipe_avcenc_mgr = upipe_avcenc_mgr_alloc(); upipe_sws_mgr = upipe_sws_mgr_alloc(); upipe_filter_blend_mgr = upipe_filter_blend_mgr_alloc(); upipe_fsink_mgr = upipe_fsink_mgr_alloc(); upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); /* null */ struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc(); upipe_null = upipe_void_alloc(upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "null")); assert(upipe_null != NULL); upipe_mgr_release(upipe_null_mgr); /* file source */ struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc(); upipe_source = upipe_void_alloc(upipe_fsrc_mgr, uprobe_pfx_alloc(uprobe_use(logger), loglevel, "fsrc")); assert(upipe_source != NULL); upipe_mgr_release(upipe_fsrc_mgr); if (!ubase_check(upipe_set_uri(upipe_source, srcpath))) exit(EXIT_FAILURE); /* upipe-ts */ struct upipe_mgr *upipe_ts_demux_mgr = upipe_ts_demux_mgr_alloc(); struct upipe_mgr *upipe_autof_mgr = upipe_autof_mgr_alloc(); upipe_ts_demux_mgr_set_autof_mgr(upipe_ts_demux_mgr, upipe_autof_mgr); upipe_mgr_release(upipe_autof_mgr); struct upipe *ts_demux = upipe_void_alloc_output(upipe_source, upipe_ts_demux_mgr, uprobe_pfx_alloc( uprobe_selflow_alloc(uprobe_use(logger), uprobe_selflow_alloc(uprobe_use(logger), &uprobe_catch, UPROBE_SELFLOW_PIC, "auto"), UPROBE_SELFLOW_VOID, "auto"), loglevel, "tsdemux")); assert(ts_demux != NULL); upipe_mgr_release(upipe_ts_demux_mgr); upipe_release(ts_demux); /* fire loop ! */ upump_mgr_run(upump_mgr, NULL); /* release everyhing */ upipe_release(upipe_source); upipe_release(upipe_split_output); upipe_release(upipe_null); uprobe_release(logger); uprobe_clean(&uprobe_catch); uprobe_clean(&uprobe_avcdec); uprobe_clean(&uprobe_uref); upipe_mgr_release(upipe_avcdec_mgr); upipe_mgr_release(upipe_avcenc_mgr); upipe_mgr_release(upipe_sws_mgr); upipe_mgr_release(upipe_filter_blend_mgr); upipe_mgr_release(upipe_fsink_mgr); upipe_mgr_release(upipe_probe_uref_mgr); udict_mgr_release(udict_mgr); umem_mgr_release(umem_mgr); upipe_av_clean(); return 0; }
/** 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; }
/** @This starts playing the given URI. * * @param glxplayer glxplayer context * @param upump_mgr upump manager of the main thread * @param uri URI to play * @param upipe_ts set to true to use Upipe's TS demux, false for libavformat * @return false in case of error */ static bool upipe_glxplayer_play(struct upipe_glxplayer *glxplayer, struct upump_mgr *upump_mgr, const char *uri, bool upipe_ts) { struct upipe *upipe_src; uprobe_pthread_upump_mgr_set(glxplayer->uprobe_logger, upump_mgr); uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_FREEZE_UPUMP_MGR); if (!upipe_ts) { /* use avformat source (and internal demuxer) */ struct upipe_mgr *upipe_avfsrc_mgr = upipe_avfsrc_mgr_alloc(); if (unlikely(upipe_avfsrc_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_avfsrc_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_selflow), glxplayer->loglevel, "avfsrc")); upipe_mgr_release(upipe_avfsrc_mgr); if (unlikely(upipe_src == NULL)) return false; if (unlikely(!ubase_check(upipe_attach_uclock(upipe_src)) || !ubase_check(upipe_set_uri(upipe_src, uri)))) { upipe_release(upipe_src); return false; } glxplayer->trickp = true; } else { /* try file source */ struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc(); if (unlikely(upipe_fsrc_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_fsrc_mgr, uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s), glxplayer->loglevel, "fsrc")); upipe_mgr_release(upipe_fsrc_mgr); if (unlikely(upipe_src == NULL)) return false; if (ubase_check(upipe_set_uri(upipe_src, uri))) { glxplayer->trickp = true; } else { upipe_release(upipe_src); glxplayer->trickp = false; /* try udp source */ struct upipe_mgr *upipe_udpsrc_mgr = upipe_udpsrc_mgr_alloc(); if (unlikely(upipe_udpsrc_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_udpsrc_mgr, uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s), glxplayer->loglevel, "udpsrc")); upipe_mgr_release(upipe_udpsrc_mgr); if (unlikely(upipe_src == NULL)) return false; if (ubase_check(upipe_set_uri(upipe_src, uri))) { upipe_attach_uclock(upipe_src); } else { upipe_release(upipe_src); /* try http source */ struct upipe_mgr *upipe_http_src_mgr = upipe_http_src_mgr_alloc(); if (unlikely(upipe_http_src_mgr == NULL)) return false; upipe_src = upipe_void_alloc(upipe_http_src_mgr, uprobe_pfx_alloc(uprobe_use(&glxplayer->uprobe_source_s), glxplayer->loglevel, "httpsrc")); upipe_mgr_release(upipe_http_src_mgr); if (unlikely(upipe_src == NULL)) return false; if (!ubase_check(upipe_set_uri(upipe_src, uri))) { upipe_release(upipe_src); return false; } } } /* upipe-ts demuxer */ struct upipe_mgr *upipe_ts_demux_mgr = upipe_ts_demux_mgr_alloc(); if (unlikely(upipe_ts_demux_mgr == NULL)) { upipe_release(upipe_src); return false; } struct upipe_mgr *upipe_mpgvf_mgr = upipe_mpgvf_mgr_alloc(); if (upipe_mpgvf_mgr != NULL) { upipe_ts_demux_mgr_set_mpgvf_mgr(upipe_ts_demux_mgr, upipe_mpgvf_mgr); upipe_mgr_release(upipe_mpgvf_mgr); } struct upipe_mgr *upipe_h264f_mgr = upipe_h264f_mgr_alloc(); if (upipe_h264f_mgr != NULL) { upipe_ts_demux_mgr_set_h264f_mgr(upipe_ts_demux_mgr, upipe_h264f_mgr); upipe_mgr_release(upipe_h264f_mgr); } struct upipe *upipe_ts_demux = upipe_void_alloc_output(upipe_src, upipe_ts_demux_mgr, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_selprog), glxplayer->loglevel, "ts demux")); if (unlikely(upipe_ts_demux == NULL)) { upipe_mgr_release(upipe_ts_demux_mgr); upipe_release(upipe_src); return false; } upipe_release(upipe_ts_demux); upipe_mgr_release(upipe_ts_demux_mgr); } if (!glxplayer->trickp) uprobe_dejitter_set(glxplayer->uprobe_dejitter, true, 0); /* prepare a queue source for the decoded video frames */ uprobe_throw(glxplayer->uprobe_logger, NULL, UPROBE_THAW_UPUMP_MGR); glxplayer->upipe_glx_qsrc = upipe_qsrc_alloc(glxplayer->upipe_qsrc_mgr, uprobe_pfx_alloc( uprobe_use(&glxplayer->uprobe_glx_qsrc_s), glxplayer->loglevel, "glx qsrc"), GLX_QUEUE_LENGTH); if (unlikely(glxplayer->upipe_glx_qsrc == NULL)) { upipe_release(upipe_src); return false; } upipe_attach_upump_mgr(glxplayer->upipe_glx_qsrc); /* prepare to transfer the source to a new thread */ glxplayer->src_xfer = upipe_xfer_mgr_alloc(XFER_QUEUE, XFER_POOL); if (unlikely(glxplayer->src_xfer == NULL)) { upipe_release(upipe_src); upipe_release(glxplayer->upipe_glx_qsrc); return false; } /* spawn a thread for the source */ if (pthread_create(&glxplayer->src_thread_id, NULL, upipe_glxplayer_source_thread, glxplayer)) { upipe_mgr_release(glxplayer->src_xfer); upipe_release(glxplayer->upipe_glx_qsrc); return false; } glxplayer->upipe_src_xfer = upipe_xfer_alloc(glxplayer->src_xfer, uprobe_pfx_alloc(uprobe_use(glxplayer->uprobe_logger), glxplayer->loglevel, "source xfer"), upipe_src); if (unlikely(glxplayer->upipe_src_xfer == NULL)) { upipe_mgr_release(glxplayer->src_xfer); upipe_release(upipe_src); upipe_release(glxplayer->upipe_glx_qsrc); return false; } /* from now on upipe_src should not be accessed */ upipe_attach_upump_mgr(glxplayer->upipe_src_xfer); glxplayer->upipe_ts = upipe_ts; glxplayer->uri = strdup(uri); return true; }
int main(int argc, char *argv[]) { assert(argc >= 2); nb_files = argc - 1; files = argv + 1; struct upump_mgr *upump_mgr = upump_ev_mgr_alloc_default(UPUMP_POOL, UPUMP_BLOCKER_POOL); assert(upump_mgr != NULL); 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); /* main probe */ struct uprobe *logger = uprobe_stdio_alloc(NULL, stderr, UPROBE_LOG_VERBOSE); assert(logger != NULL); logger = uprobe_uref_mgr_alloc(logger, uref_mgr); assert(logger != NULL); logger = uprobe_upump_mgr_alloc(logger, upump_mgr); assert(logger != NULL); logger = uprobe_ubuf_mem_alloc(logger, umem_mgr, UBUF_POOL_DEPTH, UBUF_POOL_DEPTH); assert(logger != NULL); /* file source */ struct uprobe uprobe_fsrc; uprobe_init(&uprobe_fsrc, catch_fsrc, uprobe_use(logger)); struct upipe_mgr *upipe_fsrc_mgr = upipe_fsrc_mgr_alloc(); assert(upipe_fsrc_mgr != NULL); struct upipe *upipe_fsrc = upipe_void_alloc(upipe_fsrc_mgr, uprobe_pfx_alloc(uprobe_use(&uprobe_fsrc), UPROBE_LOG_DEBUG, "file source")); assert(upipe_fsrc != NULL); upipe_mgr_release(upipe_fsrc_mgr); ubase_assert(upipe_set_uri(upipe_fsrc, files[current])); /* m3u reader */ struct upipe_mgr *upipe_m3u_reader_mgr = upipe_m3u_reader_mgr_alloc(); assert(upipe_m3u_reader_mgr != NULL); struct upipe *upipe_m3u_reader = upipe_void_alloc_output( upipe_fsrc, upipe_m3u_reader_mgr, uprobe_pfx_alloc(uprobe_use(logger), UPROBE_LOG_VERBOSE, "m3u reader")); upipe_mgr_release(upipe_m3u_reader_mgr); assert(upipe_m3u_reader != NULL); struct uprobe uprobe_uref; uprobe_init(&uprobe_uref, catch_uref, uprobe_use(logger)); struct upipe_mgr *upipe_probe_uref_mgr = upipe_probe_uref_mgr_alloc(); assert(upipe_probe_uref_mgr != NULL); struct upipe *upipe_probe_uref = upipe_void_chain_output( upipe_m3u_reader, upipe_probe_uref_mgr, uprobe_pfx_alloc(uprobe_use(&uprobe_uref), UPROBE_LOG_DEBUG, "probe uref")); upipe_mgr_release(upipe_probe_uref_mgr); assert(upipe_probe_uref != NULL); /* null output */ struct upipe_mgr *upipe_null_mgr = upipe_null_mgr_alloc(); assert(upipe_null_mgr != NULL); struct upipe *upipe_null = upipe_void_chain_output( upipe_probe_uref, upipe_null_mgr, uprobe_pfx_alloc(uprobe_use(logger), UPROBE_LOG_DEBUG, "null")); upipe_mgr_release(upipe_null_mgr); assert(upipe_null != NULL); upipe_release(upipe_null); /* run main loop */ upump_mgr_run(upump_mgr, NULL); /* release */ upipe_release(upipe_fsrc); upump_mgr_release(upump_mgr); uref_mgr_release(uref_mgr); udict_mgr_release(udict_mgr); umem_mgr_release(umem_mgr); uprobe_clean(&uprobe_fsrc); uprobe_clean(&uprobe_uref); uprobe_release(logger); return 0; }